Project 3: Memory
Build circuits that remember state across clock cycles.
Key Concept: Registers
Section titled “Key Concept: Registers”Unlike combinational circuits, sequential circuits have memory. In Hardcaml:
let spec = Reg_spec.create ~clock:i.clock ~clear:i.clear () inlet stored = reg spec input_signalDFF (D Flip-Flop)
Section titled “DFF (D Flip-Flop)”The basic memory element. Output = previous input.
let create _scope (i : _ I.t) : _ O.t = let spec = Reg_spec.create ~clock:i.clock ~clear:i.clear () in { out = reg spec i.inp }1-bit register with load enable. Only updates when load=1.
let create _scope (i : _ I.t) : _ O.t = let spec = Reg_spec.create ~clock:i.clock ~clear:i.clear () in { out = reg spec ~enable:i.load i.inp }Register
Section titled “Register”16-bit register. Use 16 Bit chips or a single 16-bit reg:
{ out = reg spec ~enable:i.load i.inp } (* inp is 16 bits *)8 registers, addressed by 3 bits.
Structure:
- DMux8Way the load signal to 8 registers
- 8 Registers all get the same input
- Mux8Way16 selects which register’s output
let loads = N2t_chips.dmux8way_ scope i.load i.address inlet r0 = N2t_chips.register_ scope i.clock i.clear i.inp loads.a in(* ... 7 more registers ... *){ out = N2t_chips.mux8way16_ scope r0 r1 r2 r3 r4 r5 r6 r7 i.address }Larger RAMs
Section titled “Larger RAMs”Build hierarchically:
- RAM64 = 8 × RAM8 (split 6-bit address: [0..2] + [3..5])
- RAM512 = 8 × RAM64
- RAM4K = 8 × RAM512
- RAM16K = 4 × RAM4K
(* RAM64: use bottom 3 bits for RAM8, top 3 for selection *)let addr_low = select i.address ~high:2 ~low:0 inlet addr_high = select i.address ~high:5 ~low:3 inPC (Program Counter)
Section titled “PC (Program Counter)”16-bit counter with priority: reset > load > inc > hold
let create scope (i : _ I.t) : _ O.t = let spec = Reg_spec.create ~clock:i.clock ~clear:i.clear () in let out = reg_fb spec ~width:16 ~f:(fun feedback -> let open N2t_chips in (* inc: out = feedback + 1 *) let incval = inc16_ scope feedback in let o1 = mux16_ scope feedback incval i.inc in (* load: out = input *) let o2 = mux16_ scope o1 i.inp i.load in (* reset: out = 0 *) mux16_ scope o2 (zero 16) i.reset ) in { out }Note: Use reg_fb for feedback loops.
Timing in Hardcaml
Section titled “Timing in Hardcaml”Important: In Hardcaml simulation, values update after Cyclesim.cycle:
inputs.inp := Bits.of_int ~width:16 42;inputs.load := Bits.vdd;Cyclesim.cycle sim;(* Now out = 42, not the old value *)This is the “post-clock-edge” view of the circuit.
Next Steps
Section titled “Next Steps”After Project 3, you have all the building blocks for a CPU:
- Logic gates (Project 1)
- ALU (Project 2)
- Registers and RAM (Project 3)
The CPU (Project 5) combines these to execute Hack machine code!