Skip to content

Project 3: Memory

Build circuits that remember state across clock cycles.

Unlike combinational circuits, sequential circuits have memory. In Hardcaml:

let spec = Reg_spec.create ~clock:i.clock ~clear:i.clear () in
let stored = reg spec input_signal

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 }

Try it in IDE →

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 }

Try it in IDE →

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 *)

Try it in IDE →

8 registers, addressed by 3 bits.

Structure:

  1. DMux8Way the load signal to 8 registers
  2. 8 Registers all get the same input
  3. Mux8Way16 selects which register’s output
let loads = N2t_chips.dmux8way_ scope i.load i.address in
let 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 }

Try it in IDE →

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 in
let addr_high = select i.address ~high:5 ~low:3 in

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.

Try it in IDE →

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.

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!