Source file clocking.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
71
72
73
74
75
open Base

module type S = Clocking_intf.S

module Make () = struct
  type 'a t =
    { clock : 'a
    ; clear : 'a
    }
  [@@deriving hardcaml]

  let add_clear t clear = { t with clear = Signal.( |: ) t.clear clear }
  let to_spec t = Reg_spec.create ~clock:t.clock ~clear:t.clear ()
  let to_spec_no_clear t = Reg_spec.create ~clock:t.clock ()
  let reg t ?enable d = Signal.reg ?enable (to_spec t) d
  let reg_no_clear t ?enable d = Signal.reg ?enable (to_spec_no_clear t) d
  let reg_fb ?enable t ~width ~f = Signal.reg_fb ?enable (to_spec t) ~width ~f

  let pipeline ?attributes ?enable t ~n d =
    Signal.pipeline ?attributes ?enable (to_spec t) ~n d
  ;;

  module Cdc = struct
    let stretch spec ~n d =
      let open Signal in
      assert (width d = 1);
      if n <= 1
      then Core.(raise_s [%message "stretch length must be >1" (n : int)])
      else (
        let n = n - 1 in
        d |: lsb (reg_fb spec ~width:n ~f:(fun s -> mux2 d (ones n) (srl s 1))))
    ;;

    let stretch_no_clear t ~n d = stretch (to_spec_no_clear t) ~n d
    let stretch t ~n d = stretch (to_spec t) ~n d

    let detect_rising_edge t s =
      let open Signal in
      let prev_s = reg_no_clear t s in
      ~:prev_s &: s
    ;;

    let with_valid_pulse_detect_rising_edge t (v : _ With_valid.t) =
      { v with valid = detect_rising_edge t v.valid }
    ;;

    let reg_no_clear_with_async_reg_annotation ~num_additional_pipeline_stages t d =
      let attribute = Rtl_attribute.Vivado.async_reg true in
      let d_false_path =
        Signal.reg (to_spec_no_clear t) d |> Fn.flip Signal.add_attribute attribute
      in
      let attributes = [ attribute ] in
      Signal.pipeline
        ~attributes
        (to_spec_no_clear t)
        ~n:num_additional_pipeline_stages
        d_false_path
    ;;
  end

  module Var = struct
    let reg ?enable clocking ~width =
      Always.Variable.reg ?enable (to_spec clocking) ~width
    ;;

    let reg_with_default ?enable clocking ~width ~clear_to =
      Always.Variable.reg
        ?enable
        (Reg_spec.override ~clear_to:(Signal.of_int ~width clear_to) (to_spec clocking))
        ~width
    ;;
  end
end

include Make ()