Verilog shift register question - Page 1
Forum section: electronics / projects

author: moffy
author_rank: Super Contributor
timestamp: April 12, 2024, 06:16:44 am
content: I am quite a noob at Verilog and am starting with a simple SPI I/F that of course needs shift registers.One thing I've noticed with the RTL schematic is that implementation 1 has a 2 input mux for every FF because the clock is ungated so when 'enable' is low the output of the FF feeds into it's input holding the last value.1.Code:module shift_reg_en #(parameter WIDTH=4)(clk, en, din, dout);input clk;input en;input din;output reg[WIDTH-1:0] dout;always @(posedge clk)beginif(en)dout <= {dout[WIDTH-2:0], din};endendmoduleThere is always the possibility of gating the clock signal, which is frowned upon because of introducing a local delay to the clock and possible glitches, but in this case (2) it looks to be guaranteed glich free with only a single 'and gate' delay. Are there any other issues with this gating or should I just accept the resource cost of the 1st solution?2.Code:module shift_reg_enclk #(parameter WIDTH=4)(clk, en, din, dout);input clk;input en;input din;output reg[WIDTH-1:0] dout;wire iclk;reg ien;always @(negedge clk)beginien <= en;endand (iclk, ien, clk);always @(posedge iclk)begindout <= {dout[WIDTH-2:0], din};endendmodule

author: microbug
author_rank: Frequent Contributor
timestamp: April 12, 2024, 10:59:53 am
content: In most FPGAs, registers do have a clock enable port. I am surprised that your tool doesn't know about this.Thedatasheet for your FPGAreferred me tothis user guidewith more details. On page 14-15 it does appear that there are clock enable ports on registers. However, there is a note sayingQuoteMy understanding is that your shift register should be using the clock enable ports, since there is only one source for the CE for all registers. I wonder if there is some configuration option or additional optimisation step that might get the tool to use the clock enable ports?If not, I wouldn't use clock gating unless you can't take the area hit from the mux implementation. You may find that the logic resources used are similar anyway, as the LUTs of the CLS blocks (groups of logic elements) may not be accessible when the block's registers are used. Unfortunately I can't find a diagram of the CLS anywhere.Some more information inthis document, section 2.1.6.

author: moffy
author_rank: Super Contributor
timestamp: April 12, 2024, 11:36:17 am
content: Thanks microbug for your advice and research, I will have to look further into it, especially as I only have their freebee IDE which while simplistic is easy to use. I am thinking that if resource utilisation is acceptable to go with solution 1 unless there is a CE. The chip I have is the GW1NR-9 for reference.

author: microbug
author_rank: Frequent Contributor
timestamp: April 12, 2024, 12:41:06 pm
content: Yes that sounds sensible. I think from the datasheet that your chip does have CE ports but the tools might not be showing them.

author: xvr
author_rank: Frequent Contributor
timestamp: April 12, 2024, 12:56:08 pm
content: Clock gating is a very bad idea.There are 2 ways of physical implementation of clock gating:Special clock buffers with clock gating (and sometimes clock switching) capability. I don't know support Gowin them or not, but in any case this is a very scared resource, and using it to implement shift register is a worst ideaUsing fabric logic to produce derived clock. FPGA has special clock tree, routed through whole chip. And syntheses process use it to achieve best possible frequencies. If you used derived clock synthesizer have to use much worse clock setup/delay timing that can be achieved by dedicated clock tree.

author: moffy
author_rank: Super Contributor
timestamp: April 14, 2024, 03:34:50 am
content: I tried the same design in Altera Quartus and there were CE pins available as microbug suggested, and I much prefer the Quartus environment and support so I think I will migrate my design efforts over to this board:https://www.amazon.com.au/Intel-Altera-Cyclone-Development-Board/dp/B0188D4ENOwhich also has a high speed USB interface for communicating to the FPGA projects, not just for programming purposes.

author: fourfathom
author_rank: Super Contributor
timestamp: April 14, 2024, 04:40:18 am
content: QuoteThis will not use clock gating, but instead will implement multiplexers at the shift register stage inputs, controlled by the en signal. When en is active D <= Q[n-1], otherwise D <= Q. The "else" is implied.In other words, this is a fully synchronous design, not clock-gated.[edit: As was noted in the original post, which I misread!]

author: BrianHG
author_rank: Super Contributor
timestamp: April 14, 2024, 04:56:29 am
content: D-Flip-flopping your 2 inputs, en and din, can be used to improve input synchronous timing and FMAX. (Not that such a small design will have trouble with FMAX)However, do not d-latch and re-clock your shift register on a latch of your clock. Otherwise, your d-out will be out of phase with your official system master CLK. This lowers FMAX by destroying your system's synchronous clock.Also, a minor logic bomb with your second code, the 'iclk' will never do anything. It will always read a stuck value if you try to shift as data through a D-FF clocked by that same signal.

author: moffy
author_rank: Super Contributor
timestamp: April 14, 2024, 05:08:20 am
content: Quote from: fourfathom on April 14, 2024, 04:40:18 amThanks, that is correct as noted in the original post it is the second example that is clock gated.

author: BrianHG
author_rank: Super Contributor
timestamp: April 14, 2024, 05:13:55 am
content: Another way to avoid the non-system sync clock.This is how I would re-write this code assuming I had a system clock of 100MHz, knowing that my data input clock was at least less than ~33MHz, my data output will be synced with my 100MHz sys clock. (Meaning that your SPI interface is not synchronous to master system clock...)My added output 'dout_ready_strobe' will pulse for only 1x 100MHz master clock when the output data is ready...Code:module shift_reg_en #(parameter WIDTH=4)(sys_clk_100MHz, din_clk, en, din, dout, dout_ready_strobe);input sys_clk_100MHz;input din_clk;input en;input din;output reg[WIDTH-1:0] dout;output reg dout_ready_strobe;reg din_clk_prev = 0;reg en_prev = 0;always @(posedge sys_clk_100MHz)begindin_clk_prev <= din_clk; // store the last state of the data input clk.en_prev <= en; // store the previous state of the data input enable.dout_ready_strobe <= ~en && en_prev ; // What I have done here is when the data input 'en' goes low, but was previously high, signifying the end of a transmitted byte, I strobe the 'dout_ready_strobe' for 1x 100Mhz clock cycle.if (din_clk && ~din_clk_prev) begin // If the 'din_clk' just went high while the previous state was low, we have determined that a low to high transition on the din_clk just occurred, now we can trigger the rest of the shift register code once.if(en)dout <= {dout[WIDTH-2:0], din};endendendendmoduleNote that it is possible to mix and match part of my code, basically the detection of the data input 'en' dropping at your system clock speed with a secondary data latch, and clocking your data input using the true data input 'clk' allowing your SPI to run at frequencies beyond you master system FPGA clock, like the example 100mhz I provided. This eats an additional byte of logic cells, but can allow for 200mhz or 400mhz SPI clock speed even if the rest of your FPGA is running at 100MHz.

author: moffy
author_rank: Super Contributor
timestamp: April 14, 2024, 05:25:45 am
content: Quote from: BrianHG on April 14, 2024, 04:56:29 amSorry I am not sure I understand what you mean? If 'en' is low before a -ve edge of 'clk', 'ien' will go low blocking the 'clk' i.e. 'iclk' to the shift register stopping any shift, but if 'en' is high before a '-ve' edge of 'clk' then 'ien' goes high and the 'clk' i.e. 'iclk' feeds through to the shift register causing a shift on each +ve 'iclk' edge, 'iclk' changes from low to 'clk'.

author: BrianHG
author_rank: Super Contributor
timestamp: April 14, 2024, 06:00:07 am
content: Quote from: moffy on April 14, 2024, 05:25:45 amBased on what you written, here is what I saw:reg iclk;always @(posedge clk) begin\iclk <= clk;ien <= en;idin <= din;endalways @(posedge iclk) begin*** all your shift register logic based on the 'i___' regs...endCorrect? (your and (xxx,xxxx,xxx) did not make any sense to me...)Now if I got this correct, the problem is only with the 'iclk'.In the first part, look at it like a 74LS74 D-FlipFlop.You tied the 'clk' input to the 74LS74 D-FF's clock input. No problem.You also tied the 'iclk' to the 74LS74 D-FF's Q data output. Ok.However, you also tied the 74LS74's D-FF's D, data input, to the 'clk', the same as it's clock input which is also wired to the 'clk'.How is the 'Q' data output supposed to function, or even cycle is that D-FF's clock input and it's data input are both wired together?If I made a mistake and you line of code:Code:and (iclk, ien, clk);actually does something weird, I have never come across such a line before. At no point do you even make 'iclk' equal to anything at all.Are you defining new module IO ports?are you trying to saywire iclk = ien && clk;If your goal was an 'and' gate delay, unfortunately, FPGA compilers have gotten smart and might erase such a delay by hard-wiring direct through their logic cell's product terms.Again, what kind of SPI speed do you need and what's your system clock frequency?When receiving the SPI, does you din and en precede, setup ready, before your clk transition? If so, all you need is your solution #1. If you go really high speed, then you will need to set you FPGA IO timing constraints to deal with that, but, we are then talking about an above 200MHz SPI bus. If your SPI bus is below 50MHz, almost anything will do.

author: moffy
author_rank: Super Contributor
timestamp: April 14, 2024, 06:14:17 am
content: Thanks BrianHG for that clarification, my code is not:reg iclk;always @(posedge clk) begin\iclk <= clk;ien <= en;idin <= din;endas you posted, but:wire iclk;reg ien;always @(negedge clk)beginien <= en;endand (iclk, ien, clk);If you look at the first RTL picture attached to the OP the logic is a bit more obvious.

author: BrianHG
author_rank: Super Contributor
timestamp: April 14, 2024, 06:44:18 am
content: That 'and (iclk, ien, clk);' is not a valid verilog code...I can only assume someone made a module called 'and',Since I did not see a timing diagram of your SPI inputs, I would have to say that solution number 1 is superior, even if it looks like more logic is being used.I don't know why you want to gate the clock.However, it is possible to do a dumb DFF serial shift register while wiring the 'en' to the serial DFF's enable inputs instead of using the 'MUX's you see in your RTL. I do not know how to do this in Gowin, but in Altera Quartus, you may assert directives to nets (in your case the 'en') so that the compiler knows to use the FF logic cell's 'enable' input allowing for what will look to be an asynchronous input with regard to the 'clk' input. Then it is your choice whether to use a posedge or negedge clk for the shift registers.If you want to do it this way, the way you would expect to see in a TTL shift register with enable input, then you would need to consult Gowin's reserved keywords to force the use of it's enable lines.The other way is to get rid of the 'if (en) begin' in your code #1 and just add a:wire iclk = clk && en;And use the 'iclk' for your always posedge clk in your first code.The question is do you want to gate the 'en'. If so, then your code #2 is one way of doing it, however, it would be simpler using one posedge clk and doing this:Code:module shift_reg_en #(parameter WIDTH=4)(clk, en, din, dout);input clk;input en;input din;output reg[WIDTH-1:0] dout;reg ien,idin;always @(posedge clk)ien <= en;idin<=din;beginif(ien)dout <= {dout[WIDTH-2:0], idin};endendmoduleNow, data and enable is synced sampled to 'clk'.Remember, your 'dout' will now be delayed by 1 additional clock, however, that is trivial to deal with as you may make a data valid strobe on the fall of 'ien' to tell the rest of your code a package was received.

author: moffy
author_rank: Super Contributor
timestamp: April 14, 2024, 07:02:42 am
content: Quote from: BrianHG on April 14, 2024, 06:44:18 amIt would be better to have given it a name 'and a1(iclk, ien, clk);', but according to the book, 'Verilog HDL by Samir Palnitkar' page 63 of the pdf I have it is valid verilog syntax.

author: BrianHG
author_rank: Super Contributor
timestamp: April 14, 2024, 07:26:08 am
content: My apologies, I exclusively learned to use the 'data flow modeling' version:IE:assign y = ~a ; // y = not aassign y = a & b ; // y = a and bassign y = a | b ; // y = a or bassign y = a ^ b; // y = a xor bassign y = a ^ ((b & c & ~d) | e) ; // y = a xor ((b and c and not d) or e)do the last one with a pile of 'and/or (out, in1, in2) with a group of interconnecting wires.See link:https://circuitfever.com/logic-gates-verilog-codethen try this one with manual single gates:assign y = (dout[7:0] == 8'b00001011) ;orassign y = (dout[7:0] == 8'd13) ;

author: moffy
author_rank: Super Contributor
timestamp: April 14, 2024, 07:40:05 am
content: I'll give it a try BrianHG and no doubt learn something also.