summaryrefslogtreecommitdiff
path: root/collatz.v
blob: 35550c28ae54224768b220192c43a62a4921808d (plain) (blame)
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
76
77
78
79
80
/**
  * Collatz Conjecture module.
  *
  * Takes a start integer and calculates the number of steps
  * required for that number to get down to 1 using the collatz
  * conjecture.
  */
module collatz (
    /* Input clock and reset pin. */
    input clk,
    input rst,

    /* The number to calculate. */
    input wire [15:0] in_start,
    /* Pulsing the start_int pin will start the calculation. */
    input wire start_int,

    /* Output count. */
    output reg [15:0] o_count,

    /* Set to high when the module is idle and ready to start.
     * While computing, this output is set to low.
     *
     * A positive edge of this will indicate the output is ready
     * to be consumed. */
    output idle
);

  // Define some state parameters.
  localparam integer IDLE = 0;
  localparam integer SPINNING = 1;

  reg state = 0;        // IDLE or SPINNING
  reg [15:0] count = 0; // Current count
  reg [15:0] n = 0;     // Current value

  wire is_even = ~n[0]; // Is the current value even.
  assign idle = state == IDLE;

  // When the start_int input is set to high, copy the in_start to the current
  // number and set the state to SPINNING.
  always @(posedge start_int) begin
    if (state == IDLE) begin
      state <= SPINNING;
      n <= in_start;
    end
  end

  // Each clock cycle, determine what needs to happen.
  always @(posedge clk or posedge rst) begin
    // On reset, reset the state.
    if (rst == 1'b1) begin
      state <= IDLE;
      count <= 0;
      n <= 0;

    // If the state is idle, reset the count to 0.
    end else if (state == IDLE) begin
      n <= 0;

    // If the state is calculating, do the next step.
    end else if (state == SPINNING) begin
      // If n is 1, then  set the output and go back to the IDLE state.
      if (n <= 1) begin
        o_count = count;
        state   = IDLE;
      end else begin
        // If is_even, divide by two, otherwise multiply by 3 and add 1.
        if (is_even) begin
          n <= n >> 1;
        end else begin
          n <= n * 3 + 1;
        end
        // Increment the count.
        count <= count + 1;
      end
    end
  end

endmodule