[Verilog/General HDL] Off-by-one error in ispLEVER fitter? Or PEBKAC? (Solved) - Page 1
Forum section: electronics / general

author: rs20
author_rank: Super Contributor
timestamp: September 06, 2017, 09:11:45 am
content: Hello,I have this blob of Verilog -- don't worry about reading the whole lot, the bold parts are the important part.input wire drdy;input wire dclk;input wire din;output reg tx;output hob;reg [7:0] counter = 0;reg [7:0] shiftreg;reg [5:0] uartcount;always @(negedge dclk)beginshiftreg <= {shiftreg[6:0],din};if (drdy)counter <= 0;else beginif (counter[4:0] == 5'd8)uartcount <= 6'd3;else if (uartcount == 6'd48)begin endelse if (uartcount[2:0] == 3'd0)uartcount <= uartcount + 6'd7;elseuartcount <= uartcount + 6'd1;if (uartcount)tx <= shiftreg[uartcount[5:4]];elsetx <= !uartcount;counter <= counter + 1;endendNow, I'm not trying to win the readable code of the year awards here, but it's my understanding that commands within a begin/end block are executed sort-of-sequentially; so on the negative edge ofdclk, the shift register first hasdinshifted into position zero. And then, sort-of-subsequently,txis assigned toone of shiftreg[0, 1, 2 or 3], based on the contents ofuartcount[5:4]. So, the the value ofdinshould be loaded into thetxregister on a single clock edge. However, if I compile/fit this using ispLEVER and inspect the fitter's output, we see that the value ofdincannot possibly make it to thetxreg in a single clock cycle; it must be transferred toshiftreg_0.Qon one cycle, and then only arrives totx.Qon the second cycle. AFAICT, this isspecificallynot what I asked for in my Verilog code above?shiftreg_0_.D = din; (1 pterm, 1 signal)shiftreg_0_.C = !dclk ; (1 pterm, 1 signal)shiftreg_1_.D = shiftreg_0_.Q ; (1 pterm, 1 signal)shiftreg_1_.C = !dclk ; (1 pterm, 1 signal)shiftreg_2_.D = shiftreg_1_.Q ; (1 pterm, 1 signal)shiftreg_2_.C = !dclk ; (1 pterm, 1 signal)shiftreg_3_.D = shiftreg_2_.Q ; (1 pterm, 1 signal)shiftreg_3_.C = !dclk ; (1 pterm, 1 signal)tx.D = uartcount_3_.Q &shiftreg_0_.Q& !uartcount_4_.Q & !uartcount_5_.Q# uartcount_3_.Q &shiftreg_1_.Q& uartcount_4_.Q & !uartcount_5_.Q# uartcount_3_.Q &shiftreg_2_.Q& !uartcount_4_.Q & uartcount_5_.Q# uartcount_3_.Q &shiftreg_3_.Q& uartcount_4_.Q & uartcount_5_.Q# !uartcount_0_.Q & !uartcount_3_.Q ; (5 pterms, 8 signals)tx.C = !dclk ; (1 pterm, 1 signal)tx.CE = !drdy ; (1 pterm, 1 signal)So, is the compiler/fitter broken, or is my understanding incorrect?

author: rs20
author_rank: Super Contributor
timestamp: September 06, 2017, 09:52:48 am
content: Well, I can answer my own question; it's a PEBKAC. When I change from the <= operator to the = operator; I see the behaviour I was expecting.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: September 06, 2017, 05:58:43 pm
content: So which line(s) did you change, and what was the resulting fitter output?

author: rs20
author_rank: Super Contributor
timestamp: September 07, 2017, 04:34:38 am
content: Ah, my design has gone through a lot of irrelevant changes since I figured out what was going on -- but I can provide I brief summary.1. First, I changedallinstances of<=with=, something like this:input wire drdy;input wire dclk;input wire din;output reg tx;output hob;reg [7:0] counter = 0;reg [7:0] shiftreg;reg [5:0] uartcount;always @(negedge dclk)beginshiftreg = {shiftreg[6:0],din};if (drdy)counter = 0;else beginif (counter[4:0] == 5'd8)uartcount = 6'd3;else if (uartcount == 6'd48)begin endelse if (uartcount[2:0] == 3'd0)uartcount = uartcount + 6'd7;elseuartcount = uartcount + 6'd1;if (uartcount)tx = shiftreg[uartcount[5:4]];elsetx = !uartcount;counter = counter + 1;endendThis basically had the effect that I wanted of having the results of assignments being carried over to "subsequent" uses of those same signals -- however, it turns out this makes the fitter equations very complicated. For example, the value oftxdepends not only on the previous value ofuartcount, but alsocounter(sinceuartcountcan be set according to the value ofcounterin "earlier" code).2. So, armed with the understanding of what was going on, I decided just to embrace the all-updates-only-happen-at-the-end nature of the<=operator; and re-ordered my code so that all reads of any given signal happenbeforeassignments to those signals. This isn't required, but I think it makes the code more readable since I'm no longer relying on the blocking or non-blocking nature of the assignments (note that this code always has a whole pile of other unrelated changes in it, so don't try to identify a 1-to-1 match in functionality):input wire drdy;input wire dclk;input wire din;output reg tx = 1;output hob;reg [7:0] counter = 8'd0;reg [7:0] shiftreg;reg [5:0] uartcount = 6'd0;always @(negedge dclk)beginif (drdy)counter <= 8'd1;else beginif (uartcount)// Datums.if (uartcount[5:4] == 2'd1)tx <= din;else if (uartcount[5:4] == 2'd2)tx <= shiftreg;elsetx <= shiftreg;elsetx <= !uartcount;if (counter[4:0] == 5'd7)uartcount <= 6'd23;else if (uartcount == 6'd0);else if (uartcount[3:0] == 4'd0)uartcount <= uartcount + 6'd7;elseuartcount <= uartcount + 6'd1;if (counter != 8'd0)counter <= counter + 1;endshiftreg <= {shiftreg[6:0],din};endThe downside is that since the code shows the shift happening at the end; I have to manually "pre-shift" the signal in my own mind (hence thetx <= din;line, and the indices being 1 & 3 instead of 2 & 4). Also, it takes a couple of clock cycles for adrdychange to flow into auartcountchange, but that's totally fine since I was waiting 8 cycles anyway and that's just the compromise you have to make for having simpler fitter equations. I don't have the fitter outputs; but it's just exactly what you'd expect from a block of Verilog that now explicitly references thedinline; obviously thedinis now present in the fitter output since I explicitly called for it.

author: ale500
author_rank: Frequent Contributor
timestamp: September 07, 2017, 02:04:09 pm
content: Not exactly knowing what you have to implement, it is difficult to know why the code you posted doesn't do it. But nonetheless I can tell you the following:QuoteYes, you asked for it !Code:always @(negedge dclk)beginshiftreg <= {shiftreg[6:0],din};tx <= shiftreg[uartcount[5:4]];endThis happens inparallel:You are loading a FF (shiftreg) with the value of dinYou are loading a FF (tx) with the value of shiftreg // let's just assume that uartcount is currently 0You see ? You asked for it.The '<=' operator means that on the event (change of the signals as per the sensitivity list of the always) new values are going to be loaded. All '<=' in an always happen in parallel and not sequentially like in C.Maybe you want to tell us what is that your code is suppose to do, I find that drawing signals (amplitude vs time) helps to visualize what I need, and then I write some HDL to achieve that. A FSM (what you have there with all those counters that doesn't really seem to make much sense to me) diagram can also help.Why does shiftreg have 8 bits when you only read 4 of them ? uartcount seems not to always get initialized, that is bad.I'd recommend you get yourself icarus verilog and gtkwave. They are very valuable in understanding/debugging verilog.You look at the equations but you don't know what exactly your code does and just modify randomly to try to "force" it the way you want it. I been that road before, many times. Don't waste your time that way, I already wasted mine without learning that much.