Source file reg_spec.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
(** Definition of clock, reset and clear signals for sequential logic (ie registers). *)

open! Core0

module type Signal = Reg_spec_intf.Signal
module type S = Reg_spec_intf.S

module Make (Signal : Signal) = struct
  type signal = Signal.t [@@deriving sexp_of]

  type t =
    { clock : signal
    ; clock_edge : Edge.t
    ; reset : signal option
    ; reset_level : Level.t
    ; clear : signal option
    }
  [@@deriving fields ~getters, sexp_of]

  let reset_exn t = reset t |> Option.value_exn
  let clear_exn t = clear t |> Option.value_exn

  let assert_non_empty typ_ t =
    if Signal.is_empty t
    then raise_s [%message "[Reg_spec] signal must not be empty" typ_ (t : signal)]
  ;;

  let assert_non_empty_or_option typ_ t = Option.iter t ~f:(assert_non_empty typ_)

  let validate { clock; clock_edge = _; reset; reset_level = _; clear } =
    assert_non_empty "clock" clock;
    assert_non_empty_or_option "reset" reset;
    assert_non_empty_or_option "clear" clear
  ;;

  let create
    ?(clock_edge = Edge.Rising)
    ?reset
    ?(reset_level = Level.High)
    ?clear
    ()
    ~clock
    =
    let t = { clock; clock_edge; reset; reset_level; clear } in
    validate t;
    t
  ;;

  let override ?clock ?clock_edge ?reset ?reset_level ?clear (spec : t) =
    let t =
      { clock =
          (match clock with
           | None -> spec.clock
           | Some clock -> clock)
      ; clock_edge = Option.value clock_edge ~default:spec.clock_edge
      ; reset =
          (match reset with
           | None -> spec.reset
           | Some reset -> Some reset)
      ; reset_level = Option.value reset_level ~default:spec.reset_level
      ; clear =
          (match clear with
           | None -> spec.clear
           | Some clear -> Some clear)
      }
    in
    validate t;
    t
  ;;
end