Lesson 4. Your own memory in the processor — and the first error
In picturesIn the processor kit's machine all memory is a single ram primitive of 256 words. In this lesson your RAM256x4 takes its place. The game will start… and begin to make mistakes: some buttons will act wrongly, and crystals will go out before they roll all the way down. This is not a build error — it's meant to happen. We'll find the cause with the built-in oscilloscope and fix it in lesson 5.
4.1. What is in the machine now and how our memory differs
Inside GW-CPU the memory is connected like this: the address is the low 8 bits of the instruction ir0–ir7, the data to write is the accumulator acc0–acc3, what is read, mq0–mq3, goes to the ALU, "write" WE = oST (the ST instruction), the clock is CPUCLK.
The ram primitive writes at the moment of the clock edge, like a flip-flop. Our memory has no clock: it writes while WE = 1 — that's a window, not an instant. So WE must get a window when the address and the data have already settled. Right after the CPUCLK 0→1 edge the processor moves to the next instruction — the address changes. By the second half of the clock cycle everything has settled. The window:
weRAM = oST · NOT CPUCLK— "this is anSTinstruction, and it's the second half of the clock cycle".
4.2. Memory at power-on — "whatever"
The ram primitive contains zeros at power-on. Latches don't: each one comes up however it happens to (in REAL — "nothing", orange; in Fast — ones). Real memory behaves the same way: at startup a computer itself puts in order whatever it is going to read.
The processor kit's game program reads two cells before it writes them: LASTB and LASTK — which buttons were pressed last time. All the others it writes first. So two instructions are added at the start of the program:
reset: LD #0 ST LASTB ; own memory: cells read before being written — clear them ST LASTKThe whole program is the file game-myram.rom.json (311 instructions).
4.3. Building
Step 1. Move the chip into the project with the machine
You built lessons 1–3 in a separate project. The chip moves over as a file:
- In the lessons 1–3 project: in the Library, in the
RAM256x4row — the ⬇ icon (save the chip to a file). All its parts go into the file too:RAM16x4,WORD4,DLatchand the gates. - Open the project with the processor kit's machine.
- In the Library header — the ⬆ icon (load a chip) → choose the file.
- If a "built differently" window appears, you already have these gates, just built differently. Keep the suggested Use mine → Import.
Step 2. Remove the memory primitive
Inside GW-CPU ("Edit"):
| Element | Action |
|---|---|
| Memory (RAM) RAM, whose output = mq0 | delete |
The labels on its pins (ir0–ir7, acc0–acc3, mq0–mq3) don't need to be deleted — the new memory will sit on them.
Step 3. Your own memory and the write window
What we build. A clock inverter, the weRAM window and RAM256x4 on the same labels.
| Element | Pin | Direction | Label |
|---|---|---|---|
| NOT | I0 | in | CPUCLK |
| NOT | O0 | out | nCLK |
| AND | I0 | in | oST |
| AND | I1 | in | nCLK |
| AND | O0 | out | weRAM |
| RAM256x4 | A0 | in | ir0 |
| RAM256x4 | A1 | in | ir1 |
| RAM256x4 | A2 | in | ir2 |
| RAM256x4 | A3 | in | ir3 |
| RAM256x4 | A4 | in | ir4 |
| RAM256x4 | A5 | in | ir5 |
| RAM256x4 | A6 | in | ir6 |
| RAM256x4 | A7 | in | ir7 |
| RAM256x4 | D0 | in | acc0 |
| RAM256x4 | D1 | in | acc1 |
| RAM256x4 | D2 | in | acc2 |
| RAM256x4 | D3 | in | acc3 |
| RAM256x4 | WE | in | weRAM |
| RAM256x4 | Q0 | out | mq0 |
| RAM256x4 | Q1 | out | mq1 |
| RAM256x4 | Q2 | out | mq2 |
| RAM256x4 | Q3 | out | mq3 |
Leave chip editing, saving the changes.
Step 4. The program
ROM (outside GW-CPU): ⚙ → ⬆ → file game-myram.rom.json.
4.4. Running it — and the error
Engine Fast, clock CPUCLK — MAX.
| What you do | What you see |
|---|---|
| power on | the clock 12:00 runs — the processor works on its own memory |
| hold A, then P | lower left hand, upper right — correct |
| hold Q | ✗ lower left hand instead of upper left |
| hold L | ✗ upper right instead of lower right |
| START | ✗ a crystal appears at the start of a pipe and goes out |
That's how it should be in this lesson. The memory is built correctly, the write window is correct in its idea — and yet a write sometimes lands in the wrong cell. Q spoils the pose cell, the crystals spoil the pipe cells.
4.5. Looking for the cause with the oscilloscope
The oscilloscope shows signals over time. To open it — the w key.
- In the add field type each of these and press
Enterafter each one:CPUCLK,ir0-7(the address bus in one row),GW-CPU.oST,GW-CPU.weRAM. - In the trig field —
GW-CPU.weRAM=1,Enter. As soon as the write window opens, the picture freezes (FROZEN), with the event in the middle. - To catch again — LIVE.
How to read it. One column is one slice: one simulator computation on a clock edge. It's the smallest unit of time the simulator has: everything that falls into one slice happens at the same time for it, with no "before" and "after".
In the highlighted slice the address has just changed (13) — and in the same slice the weRAM window opened. In real hardware there would be an instant between these events: first the new instruction settles, then the window opens. In the simulator they coincided. And on the next edge the address already jumps to the next instruction (02), and while the decoder is turning oST off, the window is not closed yet — the value manages to get written there too.
Conclusion: the write window must not open or close on the same edge where the address changes. How to achieve that without slowing the processor down endlessly — lesson 5.
Lesson 4 paste (Cmd+I)
In GW-CPU edit mode, after steps 1–2.
NOT(CPUCLK, nCLK)AND(oST, nCLK, weRAM) RAM256x4(A0=ir0, A1=ir1, A2=ir2, A3=ir3, A4=ir4, A5=ir5, A6=ir6, A7=ir7, D0=acc0, D1=acc1, D2=acc2, D3=acc3, WE=weRAM, Q0=mq0, Q1=mq1, Q2=mq2, Q3=mq3)Stuck? Something doesn't work →