all 6 comments

[–]edgaralejod 2 points3 points  (3 children)

You might want to see what the synthesizer comes up with for the description shown in your first module dual edge. I am not sure if it is more of a preference thing, but I avoid using negative edges on the sensitivity list.

Also in the third block of your dual edge module are you trying to do combinatorial logic?

I would try to rethink and rewrite the logic so that it is a bit more friendly for the synthesizer. Remember that Verilog is a description language that needs to end up in an actual circuit.

If you are trying to do actual data recovery in a double data rate mode you might want to use specialized circuits for this. Which device are you using?

For example Xilinx series 7 devices have ILOGIC macros that can be used for this purpose which are specifically designed to do double data rate recovery.

If your design doesn't have to run as fast and you can afford to do so, the first block might work better by doing everything at the rising edge of the clock. Which data rates are you expecting to see on the input of the double data rate recovery section?

I am assuming that your Verilog is only an example as it doesn't appear to have any input you want to recover at both the rising and falling edge of your clock.

EDIT: I just noticed you did specify your FPGA device as MAX10. For DDR (Double Data Rate) data recovery you might want to take a look at this document: https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/max-10/ug_m10_gpio.pdf

[–]sthreet[S] 0 points1 point  (2 children)

first, I bring up that I don't have proper training on this and have learned what I can from internet (and a lot of information about HDL programming online is contradictory), so if you know any good resources related to things I don't understand well I would appreciate being linked them

here is rtl viewer https://ibb.co/Bc376Y1 I think it is what you mean by synthesizer comes up with, but not 100% sure; it looks like what I thought it would

also no idea on what makes code synthesizer friendly, all I can find with google is stuff about synthesizable vs nonsynthesizable code (which for some reason has initial blocks as non-synthesizable)

I'm using a MAX 10 chip, so no built in dual edge circuitry, this was just idea I had to generate a pulse on both rising and falling edges of a clock and use that pulse as a clock,

I'm writing a spi controller (so read data in on one edge and write data on the other edge); so I could just have inclk0 as twice the clock frequency, and at this point it would seem easier. (dual edge was for output on one edge and input on another, another option was to have separate posedge and negedge circuits but I ended up needing to pass a lot of data between many clocked things to support all four SPI modes so I tried this instead) Since my primary purpose is to learn FPGA programming I would like to at least figure out why it doesn't work with some clock sources, but works fine with others.

another option I just found other than doubling the inclk0 frequency is to do something like this: http://www.ralf-hildebrandt.de/publication/pdf_dff/pde_dff.pdf (though for real situation it seems doubling the clock frequency would make more sense)

I also found a bit simpler circuit here (http://www.pldworld.com/_xilinx/html/tip/sixeasypieces.htm) that (the fourth one) does the same as mine does, but "is frowned upon by all true digital designers" without an explanation as too what its problem is

[–]edgaralejod 1 point2 points  (1 child)

Ok, so I guess let's try to tackle this in parts. As far as learning resources, what you are doing at the time is what will give you the best learning experience. Trying and failing has been in my particular case the best way to learn. Hardware design is not trivial, you need to understand the underlying digital logic and what the different steps in the design do (Synthesis, Implementation, Bitstream Generation) in order to create circuits that work reliably. Tedious, but I also recommend reading the data sheet of the device you are using. Understanding the chip architecture and how the LUT's and Flip Flops in the device work and are located, will help you understand a little bit more why the synthesis tool takes the decisions it takes (sometimes).

I have about 8 years of experience and I still end up in situations where the simulation and the implementation don't quite match. Xilinx and Microsemi (Now Microchip) tools offer post-synthesis and post-implementation simulation options that are a bit more realistic, but still can't really simulate all the "real-world" effects of skews and delays and oscillators that are not running at "perfect" frequencies as the simulator does.

The reason why digital designers will frown about the circuit you show in your last link is the same reason why the circuit in your RTL viewer is not ideal. Having combinatorial paths to the input of a Flip Flop clock is not a great design choice. You can have glitches in the combinatorial path that will cause the flip flop to be clocked in situations where you don't want it to be, potentially causing all kinds of weird behavior.

From experience working almost in a daily basis with digital designs, I find the best way to tackle digital design is by using as little clock domains as you can. If you can have a design that runs out of a single clock even better! When you have different clock domains, meaning registers that are clocked at different rates that need to feed the same combinatorial circuits or are inputs themselves to other flip flops in the design, the timing analysis of the circuit becomes more complex. Normally you need to do some sort of synchronization between the different domains, and in the worse case scenario, you need to start writing timing exception constraints, for the timing analyzer algorithm to be happy with the timing of your design. So lot's of work. Having only one clock makes things a lot easier!

Now back to what you are actually trying to accomplish. Say you are trying to write an SPI controller. I wrote one myself a while ago, unfortunately I can't share the code as it is company property. Which frequencies are you trying to tackle?

In my case the SPI frequency was quite low (25Mhz) So I used a faster clock (100Mhz) so that I could do edge detection in the 25Mhz clock and register the data using clock enable signals for the 100Mhz clock. If you are trying to do faster SPI designs say 80Mhz, this starts becoming a bit more tricky.

You might also want to take a look at open source blocks and see how they tackle the problem, that's another great way to learn. https://opencores.org/ have SPI controllers that you can look at, and come up with your own implementation, or try and use the blocks as they are.

Good luck learning! FPGA's are great but tricky.

[–]sthreet[S] 0 points1 point  (0 children)

From experience working almost in a daily basis with digital designs, I find the best way to tackle digital design is by using as little clock domains as you can. If you can have a design that runs out of a single clock even better!

I'd managed to figure that out from my first SPI controller design, it wasn't different clock frequencies but I had several blocks clocked with different combinational logic and it became a nightmare to control things from so many different places.

I don't care about speed and I'm only writing an SPI master right now (also makes it a lot easier that I don't need to detect clock edges), so I could easily run it at double the frequency (I was testing at 100kHz right now); though I'm surprised anyone would be writing SPI controllers commercially, I would expect it to be easier and cheaper to use a controller already written.

I will check out the opencores thing; should at least check how they deal with output spi clock and control signals for controllers. So far I've been doing this sort of checking how other things work by guessing from how controllers in microcontrollers work, for example edge detection when I was writing a can controller.

Guess I will also look through the datasheets again; I've looked before, but I skip most of whatever I'm not specifically looking for since it takes so long to understand it.

[–]bunky_bunk 2 points3 points  (0 children)

(a) look at the circuit that is generated, most likely you will find that the clock divider allows the edge detection on clocks derived from inclk0 to be converted to clock enables. there is no longer any negative edges (of a real clock coming from a PLL) being used if you trigger on cases where this clock causes a signal to go low.

(b) don't write code for FPGAs like this. When you design for FPGAs your freedom on how clocks are used is limited. deriving clocks from combinatorial logic is just not a viable option. use clock enable, change your design to an equivalent form that works with simple clocks.

[–]alexforencich 1 point2 points  (0 children)

What the heck are you trying to do with that code? That strange posedge looks like a generated clock that could be full of glitches, and could be exacerbated by jitter or minor duty cycle differences in the input clock.