Stuck with Fast Clocking Shift Register in VHDL - Page 1
Forum section: electronics / general

author: LoveLaika
author_rank: Frequent Contributor
timestamp: October 31, 2022, 09:42:45 pm
content: I'm trying to develop a parallel-in-serial-out shift register using D-flip flops for data transmission, but I'm stuck on one aspect of it. I was wondering if you guys could help me out.To better illustrate the problem of what I'm trying to achieve, consider this simple example. I have a counter running on a clock (call it CLK) at 100 MHz (period of 10 ns). My counter generates a 10-bit number in binary every clock cycle (accompanied by what I call a "data flag" to indicate that valid data is present), so I have to load it in my shift register and send out all the bits of the number before the next number gets loaded. In essence, I load a new number into the shift register on every cycle of CLK, but at the same time, my shift register is running on a second clock of 1 GHz (period of 1 ns). Let's call this clock CLK_10. With the incoming data and my "data flag" holding their value throughout one cycle of CLK and with the D-flip flops that make up the shift register running on the faster CLK_10 signal, how do I ensure that it loads once during a cycle of CLK? Most of the shift register examples I see load and shift on the same clock, but with me shifting on two different clocks, I run the risk of constantly loading the D-flip flops and not shifting properly. I thought of trying to create a single-shot "load" pulse signal, but I don't know how to do that with my faster CLK_10 and the incoming "data flag" signal. Any advice?To add a bit more detail, this is all part of an effort to try and build an 8b10b module. Now that the data encoding is done, I'm focusing on the transmission/receiving part. At first, I thought to use a finite state machine, but then when I worked on the receiving part, I switched to a shift register implementation (as that seemed to be the easiest method for incoming serial data).

author: hamster_nz
author_rank: Super Contributor
timestamp: October 31, 2022, 11:29:54 pm
content: You need to investigate what SERDES block your FPGA have. They were designed exactly to support this use case.The only other option is to Input and Output DDR, with a clock that is 5x your parallel data rate (or half your bit rate). - E.g. for a a 25MByte per second 8b10b encoded signal you can run the main logic at 25MHz, then transfer to a 125MHz clock domain to emit the bits using a DDR primitive. Obviously this DDR technique won't achieve as high a data rate as using the dedicated SERDES block will - the best you get is usually a around half the datasheet SERDES performance.The clocking requirements for SERDES are sometimes painful to get right - if you let us know what family of FPGA you are using, I might just have a sample design you can work from.

author: NorthGuy
author_rank: Super Contributor
timestamp: November 01, 2022, 02:55:33 pm
content: There may be hardware transceivers which can do this. Otherwise 1 GHz is probably too fast for an FPGA.At any rate, asasuming your CLK and CLK_10 are synchronized, you latch the data with CLK and also flip a strobe bit. Then in your CLK_10 you monitor the strobe bit. If it has changed, the new data has been set by CLK and you can now use it in CLK_10.

author: LoveLaika
author_rank: Frequent Contributor
timestamp: November 01, 2022, 07:14:44 pm
content: Thanks for your reply. I'm starting to think that everything that I need to accomplish, I can do it with FPGA primitive resources.For what it is worth, I'm using a 7-Series FPGA (KC705), though all of this is done in simulation for the time being. Following your advice, I did some research, and I found thisexample code of someone using OSERDES2 primitivesto serialize 10-bit data, which is what I'm hoping to achieve (most likely). Unfortunately, test benching the design really is painful to get right. All just trial and error I suppose, though I'm not one to give up at this point when I feel close.If I may ask, why do you say the clock has to be 5x my parallel data rate? So, my resulting packet is 10 bits. If SERDES sends one bit at a time, shouldn't it be 10x as fast so all bits are sent before new data is present? Looking at the Github serializer example's testbench code (and simulating it in Vivado), it also doesn't seem to be working in the way that I thought that it would. (I know that there are differences in application, but I thought the basic idea of the serializer would still hold regardless)

author: NorthGuy
author_rank: Super Contributor
timestamp: November 01, 2022, 08:15:38 pm
content: Quote from: LoveLaika on November 01, 2022, 07:14:44 pmKintex has GTX transceivers which can go up to 12.5 Gb/s. Look at them.Otherwise, you can go only to about 800 MHz.

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 01, 2022, 08:23:26 pm
content: Yep, but even so, on a FPGA, don't expect any moderate logic such as amanually-writtenshift registers to work at 800 MHz without great care and using standard HDL only. At some point, you'll need to define proper time constraints and use some of the dedicated internal blocks. To answer the OP's remark.Of course, anything will work in simulation as long as the logic is correct. You can simulate a complex CPU running at 10 THz. It won't work in real life.

author: BrianHG
author_rank: Super Contributor
timestamp: November 01, 2022, 08:54:35 pm
content: Quote from: SiliconWizard on November 01, 2022, 08:23:26 pmEven 800 MHz probably cannot be done without at least a DDR IO primitive, IE running your core at 400MHz with a 2x wide bus while the IO pin is sampled on the rise and again on the fall of the 400MHz core clock.Proper time constraints means understanding how to setup or write a DDR .sdc IO definition.And, don't even as about Lattice where is you want the maximum 800mbps/pin, you need to go with a 4:1 and 1:4 serializer. As for the multi-gbps transceivers, you are stuck with the FPGA vendor's primitive functions and you need to learn them inside-out if you want the true power of said IO blocks. This usually also means understanding all PLL clocking capabilities and their relations as well.

author: hamster_nz
author_rank: Super Contributor
timestamp: November 01, 2022, 09:05:19 pm
content: To sum up table 17 inhttps://docs.xilinx.com/v/u/en-US/ds182_Kintex_7_Data_SheetLVDS transmitter (using OSERDES; DATA_WIDTH = 4 to 14):Speed grade -1 - HR IO bank 950Mb/s HP IO bank 1250Mb/sSpeed grade -2 - HR IO bank 1250Mb/s HP IO bank 1400Mb/s

author: LoveLaika
author_rank: Frequent Contributor
timestamp: November 04, 2022, 02:23:32 pm
content: Quote from: NorthGuy on November 01, 2022, 08:15:38 pmThanks for the help. After much tinkering and mild annoyance, I found that my test bench was wrong...(typical user error). Turns out, I was loading undefined data which was causing my SERDES to output X, which was really bad. I figured out that the key was to have it in my code such that if the data was valid, use the data that was properly registered. Otherwise, load 0s (which, given the nature of 8b10b, I might switch to a disparity neutral code later on; just trying to get this working).I also figured out why I needed a 5x faster clock (not 10x as I thought). UG471 (alongside UG953 and UG576) have been great resources, really helping me get on the right track....although they were not easy to find. It's quite a pain to find the right user docs when they're all scattered about.

author: asmi
author_rank: Super Contributor
timestamp: November 04, 2022, 06:24:00 pm
content: You can use SelectIO Interface Wizard IP to generate just about any I/O interface (including those which use DDR or SERDES blocks) by simply setting up some parameters in the GUI. Obviously it's not as flexible as instantiating SERDES modules directly, but it covers most typical scenarios, and it's much more user-friendly. For documentation on this IP, take a look at PG070. You can both generate it as HDL to use with HDL-only designs, or add it to a diagram for connecting blocks visually.