Dear all.
I am writing some code to create clock dividers that will drive the
clock input of other synchronous logic and I have discovered a
problem that I cannot solve. The simulator shows that the logic
clocked by the derived clock is not being clocked (the internal
counter is not even reset synchronously, which leads me to believe
that the derived clock is not been caught as an even by the cascaded
divider. Please view the timing diagram on my website for details
on the output (see below)). I am hoping someone can provide some
comments on my problem since I believe this is a very common design.
I am really stumped at the fact that it doesn't work. The divider
by itself work fine.
Here is a brief description of the Verilog code for my modules which
I have attached at the end of this email:
I have a programmable clock divider module (clk_div) which I
instantiate three times in a top level module (dividers3). The
first divider is driven by one clock which I supply from a
testbench. The other two dividers are cascaded so that the divided
clock output from one divider drives the clock input of the other
divider. The input clock to the first divider in the cascade chain
is different from the input clock to the stand-alone divider, but I
noticed that it doesn't make a difference if the input clocks are
the same for both. To make things as simple as possible, all
dividers are set to divide by 2.
The funny thing about my design is that it synthesizes correctly. I
have not simulated the synthesized netlist yet, but that will be my
next step. However, I still need the fuctional model to work
correctly since I will use it in a bigger design which needs to be
simulated before it is synthesized.
Here is some additional information related to my simulation
environment:
Simulator: NC Verilog, NC Simulator Tools by Cadence, version 3.10
OS: UNIX Solaris 2.6.1
I have also tried Synopsys VCS but the problem persists.
You can also visit my website for images of my timing diagrams and
the structure of my design. Just click on the link to download the
source code and the image files as a compressed archive (~200k).
There is a README.txt file after you download and uncompress the
archive which explains how to to run the simulation with the cadence
tools, if you have them of course. There is only one script to run.
http://www.*-*-*.com/
http://www.*-*-*.com/
Thanks in advance for your help.
Nestor C.
ASIC Designer
Sapphire Research & Development, Inc.
9388 Boul. du Golf
Anjou, Quebec, Canada, H1J 3A1
Tel.: (514) 356-0634 x211
Fax.: (514) 356-0165
--
Here are the Verilog files for those who may want to take a quick at
my code without downloading the entire archive (even though it is
fairly small (~200k)):
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
// basic programmable divider module
module clk_div
(rst_in,
clk_in,
ce_in,
mod_in,
div_cnt_out,
div_clk_out
);
// -- PARAMETERS --
parameter MOD_W = 4;
// -- PORTS --
input rst_in;
input clk_in;
input ce_in;
input [MOD_W-1:0] mod_in;
output div_clk_out;
output [MOD_W-1:0] div_cnt_out;
// -- WIRES & REGISTERS --
reg [MOD_W-1:0] div_cnt;
reg div_clk_out;
// -- MAIN --
// Implement the down counter operation for clock division
begin
if (rst_in == 1'b1) begin
file://div_cnt <= {MOD_W{1'b0}};
div_cnt <= 0;
div_clk_out <= 1'b0;
end else begin
if (ce_in == 1'b1) begin
if (div_cnt == 0) begin
div_cnt <= mod_in;
div_clk_out <= 1'b1;
end else begin
div_cnt <= div_cnt - 1;
div_clk_out <= 1'b0;
end
end
end
assign div_cnt_out = div_cnt;
endmodule
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
// top level module which instantiates the above module
// three times in the configuration explained earlier.
module dividers3
(// Globals
rst_in, // global reset
sys_clk_in, // master system clock - NOT USED!
ce_in, // clock enable for sys_clk_in
// Divider Modulus settings
ref_div1_in,
ref_div2_in,
ref_div3_in,
// Input clocks
ref_clk1_in,
ref_clk2_in,
// divider 1 outputs
cnt1_out,
fb_clk_div1_out,
// divider 2 outputs
cnt2_out,
fb_clk_div2_out,
// divider 3 outputs
cnt3_out,
fb_clk_div3_out
);
//
// -- PARAMETERS --
//
parameter DIV_W = 8; // size of all dividers
//
// -- PORTS --
//
input rst_in; // global reset
input sys_clk_in; // master system clock
input ce_in; // clock enable for sys_clk_in
input [DIV_W-1 : 0] ref_div1_in,
ref_div2_in,
ref_div3_in;
input ref_clk1_in,
ref_clk2_in;
output fb_clk_div1_out,
fb_clk_div2_out,
fb_clk_div3_out;
output [DIV_W - 1 : 0] cnt1_out,
cnt2_out,
cnt3_out;
//
// -- INTERNAL WIRES & REGISTERS --
//
wire fb_clk_div2_int; // internal clock
//
// -- INSTANTIATIONS --
//
clk_div #(DIV_W) u_clk_div1
(.rst_in (rst_in),
.clk_in (ref_clk1_in),
.ce_in (ce_in),
.mod_in (ref_div1_in),
.div_cnt_out (cnt1_out),
.div_clk_out (fb_clk_div1_out)
);
clk_div #(DIV_W) u_clk_div2
(.rst_in (rst_in),
.clk_in (ref_clk2_in),
.ce_in (ce_in),
.mod_in (ref_div2_in),
.div_cnt_out (cnt2_out),
.div_clk_out (fb_clk_div2_int)
);
assign fb_clk_div2_out = fb_clk_div2_int;
clk_div #(DIV_W) u_clk_div3
(.rst_in (rst_in),
.clk_in (fb_clk_div2_int),
.ce_in (ce_in),
.mod_in (ref_div3_in),
.div_cnt_out (cnt3_out),
.div_clk_out (fb_clk_div3_out)
);
endmodule
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
// This is the testbench
module dividers3_tb;
//
// -- PARAMETERS --
//
parameter DIV_W = 8; // size of all dividers
parameter NUM_PTS = 200;
// Clock info
parameter SYS_CP = 10; // System clock period
parameter REF_CP = SYS_CP * 13;
parameter FB_CP = SYS_CP * 8;
//
// -- PORTS --
//
reg rst_in; // global reset
wire sys_clk_in; // master system clock
reg ce_in; // clock enable for sys_clk_in
reg [DIV_W-1 : 0] ref_div1_in,
ref_div2_in,
ref_div3_in;
wire ref_clk1_in,
ref_clk2_in;
wire fb_clk_div1_out,
fb_clk_div2_out,
fb_clk_div3_out;
wire [DIV_W - 1 : 0] cnt1_out,
cnt2_out,
cnt3_out;
integer i;
//
// -- INSTANTIATIONS --
//
dividers3 #(DIV_W) u_diivders3
(// Globals
.rst_in(rst_in), // global reset
.sys_clk_in(sys_clk_in), // master system clock - NOT USED!
.ce_in(ce_in), // clock enable for sys_clk_in
// Divider Modulus settings
.ref_div1_in(ref_div1_in),
.ref_div2_in(ref_div2_in),
.ref_div3_in(ref_div3_in),
// Input clocks
.ref_clk1_in(ref_clk1_in),
.ref_clk2_in(ref_clk2_in),
// divider 1 outputs
.cnt1_out(cnt1_out),
.fb_clk_div1_out(fb_clk_div1_out),
.cnt2_out(cnt2_out),
.fb_clk_div2_out(fb_clk_div2_out),
.cnt3_out(cnt3_out),
.fb_clk_div3_out(fb_clk_div3_out)
);
//
// System clock generation
//
clock_simple #(SYS_CP) u_sys_clk
(.clk_out(sys_clk_in));
// Reference clock generation
clock_simple #(REF_CP) u_ref_clk
(.clk_out(ref_clk1_in));
clock_simple #(FB_CP) u_fb_clk
(.clk_out(ref_clk2_in));
//
// -- MAIN TEST --
//
//
// Reference clock generation
//
// initial
// begin
//
// end
//
// Control Logic (OAM style)
//
initial
begin
#(SYS_CP*2+3) rst_in = 1'b1;
#(REF_CP*5) ce_in = 1'b0;
#(REF_CP*2) rst_in = 1'b0;
// Configure ref and fb clock dividers
ref_div1_in = 8'h01; // div by 2, see clk_div for usage
ref_div2_in = 8'h01; // div by 2, see clk_div for usage
ref_div3_in = 8'h01; // div by 2, see clk_div for usage
//
// For the following, provide a comparison to check the
// rising edges of the locked clocks.
//
//
// Open loop test
//
#(REF_CP*2) ce_in = 1'b1;
#(SYS_CP * NUM_PTS) ce_in = 1'b0;
//
// Close the loop now and see how it works
//
# (REF_CP * 2) ce_in = 1'b1;
#(SYS_CP * NUM_PTS * 16);
#(SYS_CP) $finish;
end
endmodule
-------------------------------------------------------------
...
read more »