forked from SJTU-YONGFU-RESEARCH-GRP/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparameterized_freq_divider.v
More file actions
executable file
·136 lines (129 loc) · 5.91 KB
/
parameterized_freq_divider.v
File metadata and controls
executable file
·136 lines (129 loc) · 5.91 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* Parameterized Frequency Divider
*
* This module implements a frequency divider with configurable division ratio
* and duty cycle. It includes safety features such as default values for invalid
* inputs and proper rounding for duty cycle calculation.
*
* Key Features:
* - Configurable division: Divide input clock by any value (≥ 2)
* - Programmable duty cycle: Control duty cycle as percentage (0-100%)
* - Default values: Uses defaults for invalid division ratios
* - Proper rounding: Duty cycle calculation includes rounding for accuracy
* - Enable control: Can pause/resume clock division
*
* Clock Division:
* - Division ratio: Output frequency = Input frequency / divide_value
* - Minimum division: divide_value must be ≥ 2
* - Default fallback: Uses DEFAULT_DIVIDE_VALUE if divide_value < 2
*
* Duty Cycle Control:
* - Duty cycle input: 0-100 percentage
* - High time calculation: high_time = (divide_value * duty_cycle + 50) / 100
* - Rounding: +50 provides proper rounding (round to nearest)
* - Special cases: 0% = always low, 100% = always high
*
* Operation:
* - Counter increments from 0 to (divide_value - 1)
* - Output is high when counter < high_time
* - Output is low when counter >= high_time
* - Counter wraps around after reaching divide_value - 1
*
* Use Cases:
* - Clock generation for subsystems
* - Frequency synthesis
* - PWM generation
* - Timing control
*
* @param COUNTER_WIDTH Width of counter (default: 16 bits)
* Maximum division ratio = 2^COUNTER_WIDTH - 1
* @param DEFAULT_DIVIDE_VALUE Default division factor (default: 2)
* Used when divide_value < 2
* @param DEFAULT_DUTY_CYCLE Default duty cycle percentage (default: 50%)
*
* @input clk_in Input clock signal
* @input rst_n Active-low reset signal
* @input enable Enable signal (high to divide, low to stop)
* @input divide_value[COUNTER_WIDTH-1:0] Division factor (must be ≥ 2)
* @input duty_cycle[6:0] Duty cycle percentage (0-100)
* @output clk_out Output divided clock
*/
module parameterized_freq_divider #(
parameter COUNTER_WIDTH = 16, // Width of counter
parameter DEFAULT_DIVIDE_VALUE = 2, // Default division factor
parameter DEFAULT_DUTY_CYCLE = 50 // Default duty cycle percentage (0-100)
) (
input wire clk_in, // Input clock
input wire rst_n, // Active low reset
input wire enable, // Enable signal
input wire [COUNTER_WIDTH-1:0] divide_value, // Division factor (must be ≥ 2)
input wire [6:0] duty_cycle, // Duty cycle percentage (0-100)
output reg clk_out // Output clock
);
// Internal counter
reg [COUNTER_WIDTH-1:0] counter;
// High time calculation based on duty cycle
wire [COUNTER_WIDTH-1:0] high_time; // Same width as counter
// ============================================================================
// High Time Calculation
// ============================================================================
// Calculate high_time based on duty cycle percentage
// Use multiplication and division to get accurate duty cycle
// Formula: high_time = (divide_value * duty_cycle + 50) / 100
// The +50 provides proper rounding (round to nearest integer)
// Example: divide_value=10, duty_cycle=33 → high_time = (10*33+50)/100 = 3.8 → 4
assign high_time = (divide_value * duty_cycle + 50) / 100; // +50 for proper rounding
always @(posedge clk_in or negedge rst_n) begin
if (!rst_n) begin
counter <= {COUNTER_WIDTH{1'b0}};
clk_out <= 1'b0;
end else if (!enable) begin
// ====================================================================
// Disabled State
// ====================================================================
// When disabled, reset counter and output
counter <= {COUNTER_WIDTH{1'b0}};
clk_out <= 1'b0;
end else begin
// ====================================================================
// Clock Division Operation
// ====================================================================
// Use default value if divide_value is invalid (less than 2)
if (divide_value < 2) begin
if (counter >= DEFAULT_DIVIDE_VALUE - 1) begin
counter <= {COUNTER_WIDTH{1'b0}};
end else begin
counter <= counter + 1'b1;
end
// Calculate high time for default
if (counter < ((DEFAULT_DIVIDE_VALUE * DEFAULT_DUTY_CYCLE) + 50) / 100) begin
clk_out <= 1'b1;
end else begin
clk_out <= 1'b0;
end
end else begin
// Normal operation with specified divide_value
if (counter >= divide_value - 1) begin
counter <= {COUNTER_WIDTH{1'b0}};
end else begin
counter <= counter + 1'b1;
end
// Set output based on duty cycle
if (duty_cycle == 0) begin
// Special case for 0% duty cycle
clk_out <= 1'b0;
end else if (duty_cycle >= 100) begin
// Special case for 100% duty cycle
clk_out <= 1'b1;
end else begin
// Normal operation with calculated duty cycle
if (counter < high_time) begin
clk_out <= 1'b1; // High portion of cycle
end else begin
clk_out <= 1'b0; // Low portion of cycle
end
end
end
end
end
endmodule