Author Topic: FPGA output not consistent with ModelSim  (Read 8384 times)

0 Members and 1 Guest are viewing this topic.

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
FPGA output not consistent with ModelSim
« on: March 20, 2022, 12:19:50 pm »
I have written a state machine in Verilog which is designed to sync to a pulse train (generated by a photodiode from a scanning laser) and then output a series of pulses. The number of pulses it outputs after each sync trigger is determined by an internal register. The design works perfectly as expected when I simulate it using ModelSim. The first screen shot below shows 5 output pulses ("pixel_clk_out") after the sync pulse ("PLL_latch_ctrl_out") which is expected as the internal register ("scan_line_clk_reset_limit") is set to 5 or "101" in binary. Upon running the same design on real hardware (Cyclone II FPGA) with a 25 MHz clock source the output is completely different (see 2nd screen shot from oscilloscope). There are far greater than 5 pulses output, yet I have confirmed that the register is holding the correct value. I have noticed other strange unpredictable behavior on the FPGA depending on whether I add additional outputs for debugging it changes the behavior despite not modifying the underlying functions of the code. I am at a loss to what is going on. Would anyone know what could potentially cause such a discrepancy between model and real implementation? I can provide code if necessary but chose to omit it for now due to the length. Thanks

Modelsim output:


FPGA output (same settings as Modelsim):
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8134
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #1 on: March 20, 2022, 12:35:23 pm »
There are 2 things you should note about using Modelsim with Quartus with regards to Cyclone II & III.

You can do a RTL simulation, or a gate level simulation, with or without IO timing accuracy.

The RTL will illustrate your HDL code's true net names in the waveform view as well as your ability to add traces of hidden nets / regs.

For the gate level sims, the nodes you see in Modelsim aren't always the same names as what you have in your HDL since you are observing internal signals inside the FPGA as well as a bunch of your code's signals may be inverted or missing all together.  For these gate level sims, only the IO pins will show true while if you went with the RTL sims, all your HDL nets will show true, but the IOs will appear to have 0ps delay.

This may be your issue.

One thing I always recommend is to learn how to use and code directly within Modelsim without Quartus writing a test-bench which sims your connected hardware.  Then bring your code into Quartus to fit into a selected FPGA.  Working in Modelsim has the vast advantage of under a second re-compile time each time you make a change to your code allowing you to flesh out everything in advance.
« Last Edit: March 20, 2022, 12:47:03 pm by BrianHG »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: FPGA output not consistent with ModelSim
« Reply #2 on: March 20, 2022, 06:30:17 pm »
Ĺook very closely at your synthesis and implementation warning. Also check initial values for registers.

Are you able to post code?
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: BrianHG

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15436
  • Country: fr
Re: FPGA output not consistent with ModelSim
« Reply #3 on: March 20, 2022, 06:34:58 pm »
Sharing code would help.

One general thought from your description. Am I right understanding your design uses its own clock, and then synchronizes to an external signal that is asynchronous to your "main" clock? If so and form your symptoms, it's likely you have a clock domain crossing issue.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #4 on: March 21, 2022, 01:10:28 am »
Sharing code would help.

One general thought from your description. Am I right understanding your design uses its own clock, and then synchronizes to an external signal that is asynchronous to your "main" clock? If so and form your symptoms, it's likely you have a clock domain crossing issue.

That is correct. It is using a 25 MHz oscillator (external to the FPGA). The asynchronous source is 2 orders of magnitude lower frequency however (on the order of 25k Hz to 250 KHz) depending on the scan rate of the laser. I previously had the same design in block form, which worked fine and I didn't have any clock domain crossing issues. These issues started after I converted my block design into Verilog. Is it possible that Verilog is synthesizing the design differently to how it would be when block format?
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: FPGA output not consistent with ModelSim
« Reply #5 on: March 21, 2022, 01:31:06 am »
EDIT: Just seen your code... looking at it now.

Common causes of such things:

- You don't have any correct clock constraints - usually a problem in higher speed clock domains. Every clock should have a constraint.

- You don't have flip-flips buffering async inputs. (gives about 1 in 100 or 1 in 1000 errors, depending on design speed)

- You don't have synchronizers on async inputs (gives about 1 in a 1,000,000 or higher error rates in what is otherwise a trustworthy design).

- Your reset strategy is not good. The design is either not properly resetting, or does flush out reset issues by design.

- You do not register your design's outputs.

- You have wrong sensitivity lists on async processes (this is a big pain).

- You have unintended latches.

- You have unintended gated clocks that are causing an issue.

- You have badly constructed clock domains. Were possible, their should be only one clock signal using in your design (so a common signal for all rising_edge()/falling_edge() for VHDL or @posedge/@negedge for Verilo).

- Where you must have clock domain crossing, they are not correctly handled.

Really we can't say what is your problem until we see code.
« Last Edit: March 21, 2022, 01:54:17 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #6 on: March 21, 2022, 01:35:27 am »
Ĺook very closely at your synthesis and implementation warning. Also check initial values for registers.

Are you able to post code?

I have initialized all registers to 0 I also have an initial reset which occurs on the first clock cycle to reset all latches, flip flops, memory etc. I will post my code below (sorry for the length)

Code: [Select]
module LaserControl (
input wire[7:0] scanline_clk_reset_limit_debug,
input data_in,
input comms_clk,
input execute,
input clk_in,
input in_a,
input in_b,
output wire ld_out,
output reg [7:0] debug_reg,
output reg debug_output);


// Control constants
localparam laser_ctrl_mode = 7;
localparam set_pixel_offset_mode = 1;
localparam set_pixel_clock_divider_mode = 5;
localparam set_pixel_scan_line_limit_mode = 6;

// Memory constants
localparam number_length = 8;

// Input data shift register
localparam IN_REG_BITS = 16;
wire in_reg_clk;
wire [IN_REG_BITS-1:0] in_reg_out;

// Internal registers
reg initial_reset = 0;
reg GLOBAL_RESET = 0;


// Variable definitions
wire [7:0] inst_decode_output; // Instruction decoder output
wire SCHMITT_OUT;
wire SCHMITT_OUT_INV;
wire PLL_latch_ctrl_out;
reg pixel_clk = 0; // Pixel clock source
wire [number_length-1:0] pixel_clk_divider_reg_out;
reg update_pixel_clk_divider_reg = 0;
reg pixel_clk_src = 0;
wire pixel_clk_out;
wire [number_length-1:0] scanline_clk_reset_limit_out;
reg update_pixel_scan_line_limit_reg = 0;
wire line_clk_reset_out;
wire [number_length-1:0] pixel_offset_reg_out;
reg update_pixel_offset_reg = 0;
wire pixel_offset_delay_trig_out;
wire pixel_offset_clk_out;
wire pixel_enable_out;
reg laser_mux_sel = 0;
reg laser_ctrl_reg = 0;
reg update_laser_ctrl_code_reg = 0;
wire[1:0] laser_ctrl_reg_out;

// Instantiate the data input shift register (using SIPO shift reg)
sipo_shift_reg #(IN_REG_BITS) in_reg ( .clk (in_reg_clk | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.s_in (data_in),
.resetn (~GLOBAL_RESET),
.enable (1),
.p_out (in_reg_out));

// UPDATE DEBUG REGister
always @(in_reg_out) begin
debug_reg <= in_reg_out[7:0];
end

// always @(pixel_offset_clk_out) begin
// debug_output <= pixel_offset_clk_out;
// end

// Input data shift register clock synchronization using D_FF (syncs input clock with FPGA clock for the data shift register)
// Instantiate the sync D_FF
d_ff sync_dff ( .clk (clk_in | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (comms_clk | ~GLOBAL_RESET),
.d (comms_clk),
.q (in_reg_clk)); // Output of this D_FF goes to the clock input of the shift register


// Instantiate instruction decoder
decoder_3to8 inst_decode ( .in (in_reg_out[2:0]),
.out (inst_decode_output));

// Initialize the PLL PD input SR latch (sync pulse)
sr_latch pd_input ( .s (in_a & in_b),
.r (~(in_b | in_a)),
.q (SCHMITT_OUT),
.q_c (SCHMITT_OUT_INV));


// Initialize the D flip flop for PLL latch reset
d_ff PLL_latch_reset ( .clk (SCHMITT_OUT_INV | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (~(line_clk_reset_out | GLOBAL_RESET)),
.d (1),
.q (PLL_latch_ctrl_out));

// Pixel clock source
always @(clk_in) begin
// On the first clock pulse, reset all registers
if(initial_reset == 0) begin
GLOBAL_RESET <= 1;
initial_reset <= 1;
end else begin
GLOBAL_RESET <= 0;
end

pixel_clk <= PLL_latch_ctrl_out & clk_in;
end

// Pixel clock divider
// This sets the pixel clock rate (how many pixels/per sec)
gated_reg #(number_length) pixel_clk_divider_reg ( .clk (update_pixel_clk_divider_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-number_length]),
.reset (GLOBAL_RESET),
.out_reg (pixel_clk_divider_reg_out));

clock_divider #(number_length) pixel_clk_divider ( .divider (pixel_clk_divider_reg_out),
.clk (pixel_clk_src | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.reset (GLOBAL_RESET),
.clk_out (pixel_clk_out));

// Scan line reset pulse
// This determines how many pixels within 1 scan line before the scan line is reset
gated_reg #(number_length) scanline_limit_reg ( .clk (update_pixel_scan_line_limit_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-number_length]),
.reset (GLOBAL_RESET),
.out_reg (scanline_clk_reset_limit_out));

clock_divider #(number_length) line_clk_divider ( .divider (scanline_clk_reset_limit_debug), // CHANGE BACK TO scanline_clk_reset_limit_out (DEBUGGING)
.clk (pixel_clk_out | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.reset (line_clk_reset_out | GLOBAL_RESET),
.clk_out (line_clk_reset_out));


// Scan line pixel offset register
// This determines how many pixels to offset a scan line from start of scan
gated_reg #(number_length) pixel_offset_reg ( .clk (update_pixel_offset_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-number_length]),
.reset (GLOBAL_RESET),
.out_reg (pixel_offset_reg_out));

clock_divider #(number_length) pixel_offset_clk_divider ( .divider (pixel_offset_reg_out),
.clk (pixel_clk | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.reset (pixel_offset_clk_out | GLOBAL_RESET),
.clk_out (pixel_offset_clk_out));

// Pixel clock enable FF from pixel offset counter
d_ff pixel_enable_ff ( .clk (pixel_offset_clk_out | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (~(line_clk_reset_out | GLOBAL_RESET)),
.d (1),
.q (pixel_enable_out));

always @(pixel_clk or pixel_enable_out) begin
pixel_clk_src <= pixel_clk & pixel_enable_out;
end

// Laser clock out selector MUX
mux21 laser_clk_out_mux ( .sel (laser_mux_sel),
.s1 (laser_ctrl_reg),
.s2 (pixel_clk_out),
.q (ld_out));

// Laser control code register
gated_reg #(2) laser_ctrl_code ( .clk (update_laser_ctrl_code_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-2]),
.reset (GLOBAL_RESET),
.out_reg (laser_ctrl_reg_out));

always @(laser_ctrl_reg_out) begin
laser_ctrl_reg <= laser_ctrl_reg_out[0] & laser_ctrl_reg_out[1];
laser_mux_sel <= laser_ctrl_reg_out[0] & ~laser_ctrl_reg_out[1];
end

// Execution control
always @(execute or inst_decode_output) begin
update_laser_ctrl_code_reg <= inst_decode_output[laser_ctrl_mode] & execute;
update_pixel_offset_reg <= inst_decode_output[set_pixel_offset_mode] & execute;
update_pixel_clk_divider_reg <= inst_decode_output[set_pixel_clock_divider_mode] & execute;
update_pixel_scan_line_limit_reg <= inst_decode_output[set_pixel_scan_line_limit_mode] & execute;
end


endmodule


 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #7 on: March 21, 2022, 01:46:40 am »
Just to add to my previous post regarding the code. There are a few instances where I ignore the edge of the clock
Code: [Select]
always @(clk_in) begin for example, where I need it to trigger on both edges to perform the logic. I am using asynchronous resets on the clock divider module (it has an internal register to keep track of how many incoming clock pulses). Without the async reset my design was not working, as by the time the next clock edge arrived the output driving reset had changed already. Again the same design worked fine in block design mode (not sure the proper name) but where you lay out the design using gates similar to circuit design. These problems started once I moved to Verilog. Thanks for the help so far @hamster_nz
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8134
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #8 on: March 21, 2022, 02:02:13 am »
Just to add to my previous post regarding the code. There are a few instances where I ignore the edge of the clock
Code: [Select]
always @(clk_in) begin for example, where I need it to trigger on both edges to perform the logic. I am using asynchronous resets on the clock divider module (it has an internal register to keep track of how many incoming clock pulses). Without the async reset my design was not working, as by the time the next clock edge arrived the output driving reset had changed already. Again the same design worked fine in block design mode (not sure the proper name) but where you lay out the design using gates similar to circuit design. These problems started once I moved to Verilog. Thanks for the help so far @hamster_nz
I believe that makes your logic operate as latch enables, enabling all the logic while 'clk_in' is high, and freezing the logic state while 'clk_in' is low.  Some logic like counters will mess up here in hardware, but may simulate differently.  If you want clocking on both edges, you need @(posedge clk_in or negedge clk_in).

In any case, it is far superior to just use the FPGA PLL to double your source clock frequency and make everything work off of a single (posedge pll_clk_out).  So, if in the future if you need further refinement, you may just set your PLL to 4x, or 8x, or 10x...

Remember, for a simple pulse and timing generator, properly written, you can most likely get your code running at 500MHz on a Cyclone II.  And if synthesizing / aligning a lock with 2ns clock alignment isn't good enough for a 250KHz signal, well...  I do have a trick which can refine that jitter period below 1ns with the 500MHz clock.
« Last Edit: March 21, 2022, 02:07:48 am by BrianHG »
 
The following users thanked this post: Someone

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: FPGA output not consistent with ModelSim
« Reply #9 on: March 21, 2022, 02:07:07 am »
Just to add to my previous post regarding the code. There are a few instances where I ignore the edge of the clock
Code: [Select]
always @(clk_in) begin for example, where I need it to trigger on both edges to perform the logic. I am using asynchronous resets on the clock divider module (it has an internal register to keep track of how many incoming clock pulses). Without the async reset my design was not working, as by the time the next clock edge arrived the output driving reset had changed already. Again the same design worked fine in block design mode (not sure the proper name) but where you lay out the design using gates similar to circuit design. These problems started once I moved to Verilog. Thanks for the help so far @hamster_nz

These look odd to me, and definitely looks like a gated clock:

Code: [Select]
d_ff pixel_enable_ff ( .clk (pixel_offset_clk_out | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (~(line_clk_reset_out | GLOBAL_RESET)),
      ...
[/code]

And this sensitivity list looks wrong:
Code: [Select]
always @(execute or inst_decode_output) begin
update_laser_ctrl_code_reg <= inst_decode_output[laser_ctrl_mode] & execute;
update_pixel_offset_reg <= inst_decode_output[set_pixel_offset_mode] & execute;
update_pixel_clk_divider_reg <= inst_decode_output[set_pixel_clock_divider_mode] & execute;
update_pixel_scan_line_limit_reg <= inst_decode_output[set_pixel_scan_line_limit_mode] & execute;
end

In general you can't do things on both edges of a clock (well,  a FF can only latch on the rising or falling edge, not both.

Still trying to understand the code... I'll let you know if I see anything.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: BrianHG

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8134
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #10 on: March 21, 2022, 02:11:20 am »
Still trying to understand the code... I'll let you know if I see anything.
Yup.  Hard to understand his true requirements.  Not compatible with my 100% synchronous coding style.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: FPGA output not consistent with ModelSim
« Reply #11 on: March 21, 2022, 03:01:56 am »
I'm pretty sure this is the bit that doesn't work. It doesn't make it though in-head Verilog to VHDL translator.

It is most likely inferring latches or something.

Code: [Select]
// Pixel clock source
always @(clk_in) begin
// On the first clock pulse, reset all registers
if(initial_reset == 0) begin
GLOBAL_RESET <= 1;
initial_reset <= 1;
end else begin
GLOBAL_RESET <= 0;
end

pixel_clk <= PLL_latch_ctrl_out & clk_in;
end

The first half should be clocked on an edge. The second half seems weird.
Code: [Select]
pixel_clk <= PLL_latch_ctrl_out & clk_in;
It show most likely be a DDR register, with the the signal inputs of "PLL_latch_ctrl_out" and "0", clocked by clk_in.

That would generate a sequence of

PLL_latch_ctrl_out , 0 , PLL_latch_ctrl_out, 0, PLL_latch_ctrl_out, 0...

With the period that matches clk_in.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15436
  • Country: fr
Re: FPGA output not consistent with ModelSim
« Reply #12 on: March 21, 2022, 03:23:06 am »
Sharing code would help.

One general thought from your description. Am I right understanding your design uses its own clock, and then synchronizes to an external signal that is asynchronous to your "main" clock? If so and form your symptoms, it's likely you have a clock domain crossing issue.

That is correct. It is using a 25 MHz oscillator (external to the FPGA). The asynchronous source is 2 orders of magnitude lower frequency however (on the order of 25k Hz to 250 KHz) depending on the scan rate of the laser. I previously had the same design in block form, which worked fine and I didn't have any clock domain crossing issues. These issues started after I converted my block design into Verilog. Is it possible that Verilog is synthesizing the design differently to how it would be when block format?

I don't know what "block format" is, so I can't answer this.

As to clock domain crossing, the "frequency" of the signals do not matter. What essentially matters is that you can get metastability issues if the external signal is not resynchronized properly, it's not a matter of frequency, but basically when edges appears relative to one another.

Those issues often lead to the exact symptoms you're seing, and the probability of metastability happening highly depends on how the code is synthesized and then placed and routed, which can be influenced by even very slight changes in your code.

Haven't looked at your code yet, but I highly suspect you haven't resynchronized the external signal properly.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #13 on: March 21, 2022, 03:26:20 am »
I'm pretty sure this is the bit that doesn't work. It doesn't make it though in-head Verilog to VHDL translator.

It is most likely inferring latches or something.

Code: [Select]
// Pixel clock source
always @(clk_in) begin
// On the first clock pulse, reset all registers
if(initial_reset == 0) begin
GLOBAL_RESET <= 1;
initial_reset <= 1;
end else begin
GLOBAL_RESET <= 0;
end

pixel_clk <= PLL_latch_ctrl_out & clk_in;
end

The first half should be clocked on an edge. The second half seems weird.
Code: [Select]
pixel_clk <= PLL_latch_ctrl_out & clk_in;
It show most likely be a DDR register, with the the signal inputs of "PLL_latch_ctrl_out" and "0", clocked by clk_in.

That would generate a sequence of

PLL_latch_ctrl_out , 0 , PLL_latch_ctrl_out, 0, PLL_latch_ctrl_out, 0...

With the period that matches clk_in.

When I used
Code: [Select]
always @(clk_in) I was under the assumption it would trigger whenever clk_in changed state. Am I mistaken here? If it is only trigger when clk_in == HIGH then it will cause problems for my code. I will change it to
Code: [Select]
always @(posedge clk_in or negedge clk_in) and see if that solves my problem. There are probably many aspects of my code that aren't ideal. I would like to learn how to do this properly as I am still a beginner when it comes to Verilog.

Also the purpose of that function (
Code: [Select]
pixel_clk <= PLL_latch_ctrl_out & clk_in; is to simply gate the clk_in with the PLL_latch_ctrl_out signal
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #14 on: March 21, 2022, 03:28:24 am »
Sharing code would help.

One general thought from your description. Am I right understanding your design uses its own clock, and then synchronizes to an external signal that is asynchronous to your "main" clock? If so and form your symptoms, it's likely you have a clock domain crossing issue.

That is correct. It is using a 25 MHz oscillator (external to the FPGA). The asynchronous source is 2 orders of magnitude lower frequency however (on the order of 25k Hz to 250 KHz) depending on the scan rate of the laser. I previously had the same design in block form, which worked fine and I didn't have any clock domain crossing issues. These issues started after I converted my block design into Verilog. Is it possible that Verilog is synthesizing the design differently to how it would be when block format?

I don't know what "block format" is, so I can't answer this.

As to clock domain crossing, the "frequency" of the signals do not matter. What essentially matters is that you can get metastability issues if the external signal is not resynchronized properly, it's not a matter of frequency, but basically when edges appears relative to one another.

Those issues often lead to the exact symptoms you're seing, and the probability of metastability happening highly depends on how the code is synthesized and then placed and routed, which can be influenced by even very slight changes in your code.

Haven't looked at your code yet, but I highly suspect you haven't resynchronized the external signal properly.

I see. If that is the case, I may have to do a big overhaul of my code. I am currently using a D flip flop to re-sync the external clock with the internal clock, but I am not sure if this is how you would do it, or if it even has the desired effect you mention.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8134
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #15 on: March 21, 2022, 03:46:49 am »

I see. If that is the case, I may have to do a big overhaul of my code. I am currently using a D flip flop to re-sync the external clock with the internal clock, but I am not sure if this is how you would do it, or if it even has the desired effect you mention.
Questions:
Why not use the external clock as your clock?
Do you need to generate output faster than that external clock?
Is that external clock too slow to PLL off of?
Or are you trying to sync to a really slow asynchronous event?
What is currently generating your 25MHz clock?

I have a sneaky suspicion your code is completely all over the place for the wrong reasons.
If we take a few steps back and works out what you are trying to achieve, I'm sure you can really eaily make a clean legible piece of synchronous verilog code.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #16 on: March 21, 2022, 04:09:43 am »

I see. If that is the case, I may have to do a big overhaul of my code. I am currently using a D flip flop to re-sync the external clock with the internal clock, but I am not sure if this is how you would do it, or if it even has the desired effect you mention.
Questions:
Why not use the external clock as your clock?
Do you need to generate output faster than that external clock?
Is that external clock too slow to PLL off of?
Or are you trying to sync to a really slow asynchronous event?
What is currently generating your 25MHz clock?

I have a sneaky suspicion your code is completely all over the place for the wrong reasons.
If we take a few steps back and works out what you are trying to achieve, I'm sure you can really eaily make a clean legible piece of synchronous verilog code.

Hi Brian, I'll do my best to explain the purpose of my code and answer your questions below

1. Why not use the external clock as your clock? The external clock has a small duty cycle. It isn't really a clock, it is a pulse. The duty cycle would be close to 0.01%. The pulse actually comes from a laser which is swept with a polygon mirror. Once the beam gets to the end of the sweep it hits a photodiode which gives out a pulse. I am using this pulse to sync the main clock which is essentially to output pulses to the laser so it can form a dot pattern. I've been able to get this working perfectly in my previous block design, but after switching to Verilog it behaves sporadically.

Do you need to generate output faster than that external clock? Yes based on above the sync pulse arrives at the end of a scan line (so much slower than the time scale I want to modulate the output). Im looking to put at least 2000 pulses out for every 1 pulse received

Is that external clock too slow to PLL off of? Because of its odd duty cycle I would say it may give problems

What is currently generating your 25MHz clock? Its a packaged crystal oscillator, I've soldered it to another board external to the FPGA, a small wire feeds that clk to the FPGA. Never had issues with that so far that I know of.


Short description of what I'm trying to do

Essentially I want to output a series of pulses to a laser to form a dotted line when its swept using a polygon mirror. These pulses need to be synced to the sweep of the laser, so a photodiode is used to detect the end of a scan line and fed to the FPGA for syncing. So far this I can get working perfectly. It only started having issues once I tried to add fancy features such as adjusting the pixel offset delay, number of pixels and the pixel clock (switched to Verilog to do this)

At the end of the day I will be reading from a memory source to output an arbitrary pattern of about 2000 pixels/pulses. To do that I plan to replace the clock source with a 2000 bit register and feed the clock source to that with an address counter and serial output.

When I first designed this I did it from the point of view as if I were designing it to work in 74 series logic gates. However as the design evolved I found it were easier to code it in Verilog on an FPGA
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #17 on: March 21, 2022, 04:14:12 am »
FYI. In case anyone is wondering what I mean by the previous design I refer to as block design I have attached a screen shot of it below

 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: FPGA output not consistent with ModelSim
« Reply #18 on: March 21, 2022, 08:39:00 am »
My Verilog skills are very poor and this is non-idiomatic Verilog, but should show how you can make a fully synchronous design for your data interfaces, in a behavioral way, not structural. It really does help to make your designs maintainable and extendable without lots of design work.

It's also got a very simplistic synchronizers for the control signals. Hopefully it helps rather than distracts.

Code: [Select]
`timescale 1ns / 1ps

module design1(
    input clk,
    // Shift register interface
    input s_data,
    input s_clock,
    input s_execute,
    input reset,
   
    // Just a generic ouput signal
    output reg ctrl
    );

    reg synced_s_data_last = 1'b0,    synced_s_data = 1'b0,    unsafe_s_data = 1'b0;
    reg synced_s_clock_last = 1'b0,   synced_s_clock = 1'b0,   unsafe_s_clock = 1'b0;
    reg synced_s_execute_last = 1'b0, synced_s_execute = 1'b0, unsafe_s_execute = 1'b0;
    reg synced_reset = 1'b0,          unsafe_reset = 1'b0;
   
    reg [15:0] shift_reg;
   
    reg[7:0] my_reg_5;
    reg[7:0] my_reg_6;
    reg[7:0] my_reg_7;
   
    always @(posedge clk) begin
        // Synchonize everyting to the fast system clock
        // Note this is a very nieve implementation of a synchronizer, but should work.
        synced_s_execute_last <= synced_s_execute;
        synced_s_execute      <= unsafe_s_execute;
        unsafe_s_execute      <= s_execute;

        synced_s_clock_last <= synced_s_clock;
        synced_s_clock      <= unsafe_s_clock;
        unsafe_s_clock      <= s_clock;

        synced_s_data_last <= synced_s_data;
        synced_s_data <= unsafe_s_data;
        unsafe_s_data <= s_data;       

        // A super-poor reset synchronizer
        synced_reset <= unsafe_reset;
        unsafe_reset <= reset;       
    end

    // Move bits into the sift register and act on them
    always @(posedge clk) begin
        if(synced_reset) begin
            // Set safe power on variables
            my_reg_5 <= 8'b10101010;
            my_reg_6 <= 8'b00000000;
            my_reg_7 <= 8'b00000000;
            shift_reg <= 16'b0000000000000000;
            ctrl <= 1'b0;
        end else begin
            // If we have seen the rising edge on the execute signal
            if(synced_s_execute_last == 1'b0 && synced_s_execute == 1'b1) begin
                // Execute the command in bits 2:0
                case(shift_reg[2:0])
                    3'b001:    ctrl     <= 1'b0; // Do something on command 1
                    3'b010:    ctrl     <= 1'b1; // Do something on command 2
                    3'b101:    my_reg_5 <= shift_reg[15:8]; // Update register values
                    3'b110:    my_reg_6 <= shift_reg[15:8];
                    3'b111:    my_reg_7 <= shift_reg[15:8];
                endcase
            end
           
            // If we have seen the rising edge on the shift register clock signal
            if(synced_s_clock_last == 1'b0 && synced_s_clock == 1'b1) begin
                // Shift in a new bit
                shift_reg <= { shift_reg[14:0], synced_s_data};
            end
        end
    end

endmodule

Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: kpow8050

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #19 on: March 21, 2022, 09:05:49 am »
Thanks for providing an alternative design. It should hopefully help me, but I will need to spend some time to understand how this works before I can implement it. What is the main difference between behavioral and structural? I'm assuming my current design was structural? Also I forgot to mention I'm actually dealing with 3 CLK signals! 1 CLK source comes from an external microcontroller which clocks the shift register interface, the other CLK source is the main (25 MHz) and a third CLK source which is an async pulse also external
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: FPGA output not consistent with ModelSim
« Reply #20 on: March 21, 2022, 09:37:49 am »
Shtuchtual is 'connect these bits together like this'

Behavioral is "I want the design to act this ways'

Most modules are a bit of both. Some things wired together, and some logic/code describing how things should work

The easy way to resolve the issue of having so many clocks it to sample the slower clock signals using a much faster system clock. You can then use the current and prior samples to work out where the edges were.

For example, you might find your photodiode has a rising edge every 25,000 system clocks, and use that information to time your laser diode  pulses.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #21 on: March 21, 2022, 10:05:26 am »
I see. My first design was more like connecting bits together, which was intuitive for me as I look at an FPGA as like a CPLD
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #22 on: March 21, 2022, 10:12:34 am »
I have modified my design somewhat. Firstly I removed all the intermediate registers and therefore was able to remove all of the always# statements except the one for the main clock. So essentially all registers are replaced with wires. I have used the assign statement for the replacements, where combinational logic was actually required. The new code actually has somewhat fixed my issues. I now get a stream of pulses somewhat resembling what I expect, although there is still some unpredictable behavior. For instance the clock divider only seems to work in multiples of 1, 2, 4, 8, 16, 32 etc. Anything between it gives funny outputs. The code is shown below

Code: [Select]
module LaserControl (
//input wire[7:0] scanline_clk_reset_limit_debug,
input data_in,
input comms_clk,
input execute,
input clk_in,
input in_a,
input in_b,
output wire ld_out,
output wire [7:0] debug_reg,
output reg debug_output);


// Control constants
localparam laser_ctrl_mode = 7;
localparam set_pixel_offset_mode = 1;
localparam set_pixel_clock_divider_mode = 5;
localparam set_pixel_scan_line_limit_mode = 6;

// Memory constants
localparam number_length = 8;

// Input data shift register
localparam IN_REG_BITS = 16;
wire in_reg_clk;
wire [IN_REG_BITS-1:0] in_reg_out;

// Internal registers
reg initial_reset = 0;
reg GLOBAL_RESET = 0;


// Variable definitions
wire [7:0] inst_decode_output; // Instruction decoder output
wire SCHMITT_OUT;
wire SCHMITT_OUT_INV;
wire PLL_latch_ctrl_out;
wire pixel_clk; // Pixel clock source
wire [number_length-1:0] pixel_clk_divider_reg_out;
wire update_pixel_clk_divider_reg;
wire pixel_clk_src;
wire pixel_clk_out;
wire [number_length-1:0] scanline_clk_reset_limit_out;
wire update_pixel_scan_line_limit_reg;
wire line_clk_reset_out;
wire [number_length-1:0] pixel_offset_reg_out;
wire update_pixel_offset_reg;
wire pixel_offset_delay_trig_out;
wire pixel_offset_clk_out;
wire pixel_enable_out;
wire laser_mux_sel;
wire laser_ctrl_reg;
wire update_laser_ctrl_code_reg;
wire[1:0] laser_ctrl_reg_out;

// Instantiate the data input shift register (using SIPO shift reg)
sipo_shift_reg #(IN_REG_BITS) in_reg ( .clk (in_reg_clk | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.s_in (data_in),
.resetn (~GLOBAL_RESET),
.enable (1),
.p_out (in_reg_out));


// Input data shift register clock synchronization using D_FF (syncs input clock with FPGA clock for the data shift register)
// Instantiate the sync D_FF
d_ff sync_dff ( .clk (clk_in | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (comms_clk | ~GLOBAL_RESET),
.d (comms_clk),
.q (in_reg_clk)); // Output of this D_FF goes to the clock input of the shift register


// Instantiate instruction decoder
decoder_3to8 inst_decode ( .in (in_reg_out[2:0]),
.out (inst_decode_output));

// Initialize the PLL PD input SR latch (sync pulse)
sr_latch pd_input ( .s (in_a & in_b),
.r (~(in_b | in_a)),
.q (SCHMITT_OUT),
.q_c (SCHMITT_OUT_INV));


// Initialize the D flip flop for PLL latch reset
d_ff PLL_latch_reset ( .clk (SCHMITT_OUT_INV | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (~(line_clk_reset_out | GLOBAL_RESET)),
.d (1),
.q (PLL_latch_ctrl_out));

// Pixel clock source
always @(posedge clk_in) begin
// On the first clock pulse, reset all registers
if(initial_reset == 0) begin
GLOBAL_RESET <= 1;
initial_reset <= 1;
end else begin
GLOBAL_RESET <= 0;
end
end

assign debug_reg = in_reg_out[7:0];
assign pixel_clk = PLL_latch_ctrl_out & clk_in;

// Pixel clock divider
// This sets the pixel clock rate (how many pixels/per sec)
gated_reg #(number_length) pixel_clk_divider_reg ( .clk (update_pixel_clk_divider_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-number_length]),
.reset (GLOBAL_RESET),
.out_reg (pixel_clk_divider_reg_out));

clock_divider #(number_length) pixel_clk_divider ( .divider (pixel_clk_divider_reg_out),
.clk (pixel_clk_src | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.reset (GLOBAL_RESET),
.clk_out (pixel_clk_out));

// Scan line reset pulse
// This determines how many pixels within 1 scan line before the scan line is reset
gated_reg #(number_length) scanline_limit_reg ( .clk (update_pixel_scan_line_limit_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-number_length]),
.reset (GLOBAL_RESET),
.out_reg (scanline_clk_reset_limit_out));

clock_divider #(number_length) line_clk_divider ( .divider (scanline_clk_reset_limit_out), // CHANGE BACK TO scanline_clk_reset_limit_out (DEBUGGING)
.clk (pixel_clk_out | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.reset (line_clk_reset_out | GLOBAL_RESET),
.clk_out (line_clk_reset_out));


// Scan line pixel offset register
// This determines how many pixels to offset a scan line from start of scan
gated_reg #(number_length) pixel_offset_reg ( .clk (update_pixel_offset_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-number_length]),
.reset (GLOBAL_RESET),
.out_reg (pixel_offset_reg_out));

clock_divider #(number_length) pixel_offset_clk_divider ( .divider (pixel_offset_reg_out),
.clk (pixel_clk | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.reset (pixel_offset_clk_out | GLOBAL_RESET),
.clk_out (pixel_offset_clk_out));

// Pixel clock enable FF from pixel offset counter
d_ff pixel_enable_ff ( .clk (pixel_offset_clk_out | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.resetn (~(line_clk_reset_out | GLOBAL_RESET)),
.d (1),
.q (pixel_enable_out));

//always @(pixel_clk or pixel_enable_out) begin
assign pixel_clk_src = pixel_clk & pixel_enable_out;
//end

// Laser clock out selector MUX
mux21 laser_clk_out_mux ( .sel (laser_mux_sel),
.s1 (laser_ctrl_reg),
.s2 (pixel_clk_out),
.q (ld_out));

// Laser control code register
gated_reg #(2) laser_ctrl_code ( .clk (update_laser_ctrl_code_reg | (GLOBAL_RESET & clk_in)), // Synchronous reset added
.data (in_reg_out[IN_REG_BITS-1:IN_REG_BITS-2]),
.reset (GLOBAL_RESET),
.out_reg (laser_ctrl_reg_out));

//always @(laser_ctrl_reg_out) begin
assign laser_ctrl_reg = laser_ctrl_reg_out[0] & laser_ctrl_reg_out[1];
assign laser_mux_sel = laser_ctrl_reg_out[0] & ~laser_ctrl_reg_out[1];
//end

// Execution control
//always @(execute or inst_decode_output) begin
assign update_laser_ctrl_code_reg = inst_decode_output[laser_ctrl_mode] & execute;
assign update_pixel_offset_reg = inst_decode_output[set_pixel_offset_mode] & execute;
assign update_pixel_clk_divider_reg = inst_decode_output[set_pixel_clock_divider_mode] & execute;
assign update_pixel_scan_line_limit_reg = inst_decode_output[set_pixel_scan_line_limit_mode] & execute;
//end


endmodule


I have attached photos of the laser output (showing this code now works ~ sort of, not perfect yet but better than before after removing the registers)

CLK divider = 1


CLK divider = 2


CLK divider = 4


As you can see the laser dots compress with a larger clock divider (pulses come out slower for the same unit time/angular velocity of the rotation for the mirror) so that part makes sense. However I can't choose a CLK divider between 2 and 4 or 4 and 8, the output goes haywire, which is not consistent with my modelsim results still
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #23 on: March 21, 2022, 10:17:21 am »
Also I am not sure if this is related to my FPGA output not being consistent with ModelSim, but the compiler states that timing requirements aren't met. The details are listed below

Critical Warning (332148): Timing requirements not met
Info (332146): Worst-case setup slack is -1.068
   Info (332119):     Slack End Point TNS Clock
   Info (332119): ========= ============= =====================
   Info (332119):    -1.068       -11.490 clk_in
Info (332146): Worst-case hold slack is -3.219
   Info (332119):     Slack End Point TNS Clock
   Info (332119): ========= ============= =====================
   Info (332119):    -3.219        -9.698 clk_in
Info (332146): Worst-case recovery slack is -0.773
   Info (332119):     Slack End Point TNS Clock
   Info (332119): ========= ============= =====================
   Info (332119):    -0.773        -2.024 clk_in
Info (332146): Worst-case removal slack is 0.000
   Info (332119):     Slack End Point TNS Clock
   Info (332119): ========= ============= =====================
   Info (332119):     0.000         0.000 clk_in
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8134
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #24 on: March 21, 2022, 07:44:25 pm »
Ok, I have an idea of what you want to do.  If you will be adding functions, your task will grow exponentially difficult with your current coding attempts to rewrite 74LS logic gates into Verilog HDL.  I have some time today, Wednesday and Thursday and I'm willing to help you properly learn/rewrite HDL your design properly using the abilities in Verilog so you will not have trouble adding functions.

As it stands, adding more features will grow the complexity and ability to work out bugs in your design.  What you want to do isn't difficult and with a little guidance, you can have it properly working in a day or 2, even with 2048 bytes of ram which you and address and change in realtime to draw any dotted pattern you like.

If so, we will begin with your basic functionality you requested.  If you have a current testbench .v code, can you supply it?  If we begin, we would work directly in Modelsim alone to generate exactly what you like and see the FPGA perform exactly that way when you finally compile in Quartus.

 
The following users thanked this post: kpow8050


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf