ArticleDirectory
- 1 From counter to Divider
- 2 even-number Divider
- 3. Odd-number Divider
Reader's assumptions
Mastered:
- Programmable Logic Basics
- Base on OpenGL
- Verilog us II Getting Started Guide designed with OpenGL
- ModelSim Getting Started Guide designed with OpenGL
Content 1 from counter to Divider
The divider mentioned here refers to the module that reduces the input clock frequency and then outputs the clock. Today, we will only discuss the even and odd division of duty cycles. We will not discuss the fractional division and frequency doubling. If you are interested, you can study them on your own. Before that, let's take a look at the Modulo-M counter mentioned above.
Code1.1 Modulo-M counter (default: Modulo-10 counter)
Module mod_m_bin_counter # (Parameter M = 10) // mod-M (// global clock and Asyn reset input CLK, input rst_n, // Counter Interface output max_tick, output min_tick, output [N-1: 0] Q); // signal declarationlocalparam n = log2 (m); // Number of BITs in counterreg [N-1: 0] r_reg; wire [N-1: 0] r_next; // body // registeralways @ (posedge CLK, negedge rst_n) if (! Rst_n) r_reg <= 0; else r_reg <= r_next; // next-state logicassign r_next = (r_reg = (M-1 ))? 0: r_reg + 1 'b1; // output logicassign q = r_reg; assign max_tick = (r_reg = (M-1 ))? 1 'b1: 1' B0; // log2 constant functionfunction integer log2 (input integer N); integer I; begin log2 = 1; for (I = 0; 2 ** I <n; I = I + 1) log2 = I + 1; endendfunction endmodule
Based on this Modulo-M counter, We will write another testbench.
Code 1.2 Modulo M-counter testbench (reconfigured as a modulo-10 counter)
'Timescale 1ns/1 nsmodule f_div_tb; localparam T = 20; // clock periodlocalparam M = 10; localparam n = log2 (m); // global clock and Asyn resetreg CLK, rst_n; wire o_clk; // counter interfacewire max_tick, min_tick; wire [N-1: 0] q; // log2 constant functionfunction integer log2 (input integer N); integer I; begin log2 = 1; for (I = 0; 2 ** I <n; I = I + 1) log2 = I + 1; endfunction // clcokalwaysbegin CLK = 1' B0; # (T/2); CLK = 1 'b1; # (T/2); End // resetinitialbegin rst_n = 1' B0; # (T/2) rst_n = 1' B1; end // instmod_m_bin_counter #(. M (m) m_inst (. CLK (CLK ),. rst_n (rst_n ),. max_tick (max_tick ),. min_tick (min_tick ),. q (q); // stimulus bodyinitial begin // initial input @ (posedge rst_n); // wait to deassert rst_n @ (negedge CLK ); // wait for a clock // run 1024 cock cycle repeat (1024) @ (negedge CLK); // last 1024 clock cycle $ stop; endendmodule
However, the following error message is displayed when I use the Quartus II + modelsim_altera simulation.
The first line of code 2, the variable N is undefined, and the second line uses N to index the Q array. It's strange that I can use both Quartus II and the RTL view is correct. Why cannot I define modelsim_altera like this? Cough: Replace the constant (localparam) with the parameter (parameter.
Mod-M counter after code 1.3 improvement (reconfigured as mod-10 counter)
module mod_m_bin_counter # (Parameter M = 10, n = log2 (m )) // mod-M (// global clock and Asyn reset input CLK, input rst_n, // Counter Interface output max_tick, output min_tick, output [N-1: 0] Q ); // signal declaration // localparam n = log2 (m); // Number of BITs in counterreg [N-1: 0] r_reg; wire [N-1: 0] r_next; // body // registeralways @ (posedge CLK, negedge rst_n) if (! Rst_n) r_reg <= 0; else r_reg <= r_next; // next-state logicassign r_next = (r_reg = (M-1 ))? 0: r_reg + 1 'b1; // output logicassign q = r_reg; assign min_tick = (r_reg = 0 )? 1 'b1: 1' B0; assign max_tick = (r_reg = (M-1 ))? 1 'b1: 1' B0; // log2 constant functionfunction integer log2 (input integer N); integer I; begin log2 = 1; for (I = 0; 2 ** I
After the modification is complete, you can combine it in Quartus II. Next, follow the [documentation]. Amy electronics-perform another simulation using the Verilog us II entry guide designed by using OpenGL. Tell everyone a trick. If you perform an RTL-level or gate-level simulation, Quartus II will generate the do file for our main module and Its testbench. In this case, if an error occurs, you do not need to restart modelsim_altera. You only need to load the do file again.
(Path format: Quarter II Project Folder \Simulation \ Modelsim\ Mod_m_bin_counter_run_msim_rtl_verilog.do)
Let's take a look at the RTL-level simulation waveform.
Next we will discuss how to measure the waveform length. We should pay attention to the two tools. In Modelsim> Windows, open the tool. Add a few cursor to the waveform, and use the mouse to adjust its position.
Note the red area and ID. We can clearly see that the distance between the two cursor is 20,000 ps, that is, 20 NS, that is, the period of the Modulo-10 counter. So how can we make it display 20 NS? In the Axis area (), right-click and select to set the time unit.
Change to NS. By the way, measure the duration of the max_tick and min_tick pulses, as shown below:
After the measurement, you can use it to remove unnecessary cursor.
For a different perspective.
Suppose we use max_tick as the enable signal to flip a register, then this variable will output a square wave, and its cycle is twice the period of the mode-M.
This is the principle of an even-number divider.
If we use the rising and falling sides of the global clock to trigger the counter, then generate the clock based on the values of the two counters, and then use the two clock operations to obtain the clock that requires the frequency division. The following uses the Modulo-3 counter as an example to describe how to divide the system by three.
Method 1
The yellow area triggers the counter using the rising and falling sides of the global clock respectively. The green area generates two pulse signals based on the output Q of the two counters. The blue area is the required frequency clock.
The green area is 0 ~ 3> 1. Low output level; 3> ~ 3-1 outputs a high level. The corresponding green area performs bitwise OR operations.
Method 2
The green area is 0 ~ 3> 1. output high level, 3> ~ 3-1 output low level. The corresponding green area performs bitwise AND operations.
The above is the principle of Technology Division.
2 even-number Divider
Based on the analysis in section 1st, We will write an even-number crossover case.
Code 2.1 even division (default division ratio is 50,000,000)
Module f_div # (parameter ratio = 50_000_000) (// global clock and Asyn reset input CLK, input rst_n, // output clock output Reg o_clk); wire max_tick; mod_m_bin_counter #(. M (ratio/2) mod_m_inst (. CLK (CLK ),. rst_n (rst_n ),. max_tick (max_tick ),. min_tick (),. q (); always @ (posedge CLK, negedge rst_n) if (! Rst_n) o_clk <= 1 'b0; else if (max_tick) o_clk <= ~ O_clk; endmodule
22nd ~ In the 26 rows, we use the max_tick of the Modulo-M counter as the clock to drive the o_clk flip. Note that in the Modulo-M sample parameter of the first row, the value of M is half of the ratio of the dividing ratio (ratio.
Testbench is given below.
Code 2.2: testbench with an even division (reconfigured to 6 Division)
'Timescale 1ns/1 nsmodule f_div_tb; localparam ratio = 6; localparam T = 20; // clock period // global clock and Asyn resetreg CLK, rst_n; wire o_clk; // clcokalwaysbegin CLK = 1' B0; # (T/2); CLK = 1' B1; # (T/2); End // resetinitialbegin rst_n = 1' B0; # (T/2) rst_n = 1' B1; end // instf_div #(. ratio (ratio) f_div_inst (. CLK (CLK ),. rst_n (rst_n ),. o_clk (o_clk); // stimulus bodyinitial begin // initial input @ (posedge rst_n); // wait to deassert rst_n @ (negedge CLK ); // wait for a clock // run 1024 cock cycle repeat (1024) @ (negedge CLK); // last 1024 clock cycle $ stop; endendmodule
The following figure shows the RTL-level simulation waveform. Observe the distance between the three cursor, which are 120ns and 20ns respectively. That is, the split-frequency operation is achieved.
3. Odd-number Divider
After talking about the even-number division, let's write an odd-number division.
Code 3.1 odd Division (25 division by default)
Module f_div # (parameter ratio = 25) (// global clock and Asyn reset input CLK, input rst_n, // output clock output o_clk_p, o_clk_n, o_clk ); // log2 constant functionfunction integer log2 (input integer N); integer I; begin log2 = 1; for (I = 0; 2 ** I <n; I = I + 1) log2 = I + 1; endfunctionlocalparam n = log2 (ratio); wire [N-1: 0] q_pos, q_neg; mod_m_bin_counter #(. M (ratio) mod_m_inst1 (. CLK (CLK ),. rst_n (RST _ N),. max_tick (),. min_tick (),. Q (q_pos); mod_m_bin_counter # (. m (ratio) mod_m_inst2 (. CLK (~ CLK),. rst_n (rst_n),. max_tick (),. min_tick (),. Q (q_neg); assign o_clk_p = (q_pos <= ratio> 1 )? 0: 1; assign o_clk_n = (q_neg <= ratio> 1 )? 0: 1; assign o_clk = o_clk_n | o_clk_p; endmodule
24th ~ 31 lines and 33rd ~ For 40 rows, we have made two Modulo-M counters with the same parameters. The difference lies in the differences between 26th rows and 35th rows, that is, the trigger of the rising edge and the trigger of the falling edge.
Testbench is given below.
Code 3.2 odd-division testbench (reconfigured to 5-Division)
'Timescale 1ns/1 nsmodule f_div_tb; localparam ratio = 5; localparam T = 20; // clock period // global clock and Asyn resetreg CLK, rst_n; wire o_clk_p, lead, o_clk; // clcokalwaysbegin CLK = 1' B0; # (T/2); CLK = 1' B1; # (T/2); End // resetinitialbegin rst_n = 1' B0; # (T/2) rst_n = 1' B1; end // instf_div #(. ratio (ratio) f_div_inst (. CLK (CLK ),. rst_n (rst_n ),. o_clk_p (o_clk_p ),. o_clk_n (o_clk_n ),. o_clk (o_clk); // stimulus bodyinitial begin // initial input @ (posedge rst_n); // wait to deassert rst_n @ (negedge CLK ); // wait for a clock // run 1024 cock cycle repeat (1024) @ (negedge CLK); // last 1024 clock cycle $ stop; endendmodule
The following shows the RTL-level simulation waveform. The range of the cursor in the Red Circle is displayed, and the frequency is 5.
Well, today I will be here. If you have any questions, please leave a message to discuss them.
Reference
[Notes]. Several writing methods for the same duty cycle divider. [OpenGL]
See also
[Study FPGA/FPGA with Amy]. [logical experiment document serialization plan]