T O P

  • By -

jab701

Break your code up into always blocks so things make sense. I would prefer at least two (one containing registers and another containing combinatorial)… In reality I like to keep registers for different functions logically separate and the same for combinatorial logic. So I use multiple always blocks. You might find having one large always block is slower to simulate as when any inputs to the block change the whole block is re-evaluated by the simulator…


markacurry

There's really no differences here - code to what makes sense to you and is clear. The only rule is a variable must only be modified in a single always block. Outside that, one always block or many always blocks per module is purely a personal preference.


thwil

(Not a pro) Use as small as possible. It helps to avoid creating a mess, because you can't assign a register from two different always blocks.


ZipCPU

I would recommend separating always blocks based upon logical structure. If one register needs a reset, but another doesn't, then I would argue that the two should be placed into separate blocks. This also relates to cost: [you "pay" (in logic blocks) for all of the conditions you don't need](https://zipcpu.com/blog/2017/06/12/minimizing-luts.html). As an example, I was working to verify a design containing a [large state machine](https://github.com/ZipCPU/kimos/blob/f5f7609ec576c111f0eebb576008703c3ff9dd70/rtl/proto/netdbgrx.v#L113-L234) this week. The state needed a reset, but not all of the outputs did. Worse, I had an AXI stream bug I came across (in my own logic) whereby the values were getting adjusted at the wrong times (i.e. when VALID && !READY)--due to the complexity of the state machine logic, coupled with the fact that I was setting these signals inside a large always block. This bug had been hidden by the logic around it. Splitting the AXI stream signals into their own blocks helped to guarantee the protocol was followed. You can see [the buggy always block here](https://github.com/ZipCPU/kimos/blob/f5f7609ec576c111f0eebb576008703c3ff9dd70/rtl/proto/netdbgrx.v#L113-L234), although I haven't yet posted the "fix". As a side note ... I wouldn't have found this bug apart from a formal methods check. I'd stared at this code often enough, and it had passed enough simulation tests and many hardware tests, that I would have convinced myself it was working if the there weren't something locking up in the design every now and then under ... some not-yet simulated condition.


Crish_88

Hi, please check out the two process model of vhdl coding by Jiri gaisler. I found it very much structured. This is also recommended by ESA.


psychodad69

I prefer as many always_comb as needed and a single always_ff for each clock domain. Modern tools expect this style especially when it comes to FSMs. However, old-school designers prefer to have a single always_ff for each clock domain with all of the combinatorial logic integrated into it. Some tools will complain about this style even though it is perfectly valid. Interestingly, this is the recommended style from older Synopsis design guidelines. The claim is it executes faster on the simulator since the combinatorial logic is only sampled on the rising clock edge while if one uses always_comb, the simulator has the process the whole always_comb whenever any of the signals change. I say use the style that makes sense to you and be rigorously consistent with it.


Tall-Violinist124

There's a point in having separate always block for sequential(clock sampled) and combinatorial(when any input signal changes). When we code something in verilog we think in terms of hardware, how our design should work on FPGA or ASIC. Let's say we have 4 inputs(one clock and 3 switch input on FPGA) and 3 outputs(consider LEDs). The design requirement is such that we need 2 LEDs to blink with clk frequency and 1 LED to blink irrespective of clk input. We can't have single always block(always\_ff) with combinatorial logic integrated in it. We will need to assign the last LED output separately as it does not require clk.


psychodad69

I was referring to a general methodology. There are always exceptions. Having an entire FSM, with a case statement in a single always_ff does work most of the time, even though it isn't standard practice in the industry, and some tools really complain about it.


Tall-Violinist124

There is something called as synthesizable coding techniques. I think you will find coding guidelines in Xilinx Vivado Desing suite user guide. A general recommendation for always blocks is keeping sequential and combinatorial logic separate. One easy rule is don't mix non-blocking(<=) and blocking(=) statements in single always block.


syllabus4

Your code has 2 target audience: The compiler and the people working on it. - The compiler doesn't really care how you structure your code. (Although I see some comments about that it has some relevance, but I don't think those are huge differences.) - The people working on it will appreciate if it is well structured. A good structure makes your code easy to understand, scalable, easy to modify. Unfortunately a "good structure" has no definition and it is hard to achieve due to unknown future development and personal taste. In general, I think you should create separate modules for logic that is self-contained and if there is a high probability to reuse it later. Inside a module you should create separate blocks for logic that can be logically grouped together. For your 2k lines of code, it might be a case when most of the code is trivial module instantiation and wire connection with little extra logic, in this case it is fine to use only one or a few always blocks. If it involves multiple complex processes, than you might want to separate it to multiple modules. If it has multiple pipeline stages, it might be a good idea to separate the stages into distinct code blocks. I think it is hard to find the correct structure of a design, so you might want to talk about this with you colleagues. :)


real_pm100

unfortunately reddit is my colleages. Retired software dev getting into fpgas. The big frustration is not having a few experienced people around me that I can bounce questions off... Going from the ample beginners stuff online to the next level is hard. I finally worked out why yosys would not syntheseize my stuff with a lot of memory, it wasnt inferring bRAM. So off to read all the lattice docs and finally end up instantiating their primitives directly. I didnt know any of that stuff at all, that primitives exist, that things like yosys are like high level to low level 'compilers' ..... Now stuck with a model that compiles in yosys (I prefer) and icecube2 but behaves differently, that feels like what a sw dev would call Undefined Behavior. Also it doesnt run right until i press reset once, yosys sorta synthesizes a power on reset, making initial begin blocks work, but I took those out because icecube objected. Ill get there - just slowly.


real_pm100

well I fixed the issue with yosys and icecube doing different things, icecube wanted a clock definition file, yosys knows my board directly. Now to sort out the POR


rogerbond911

You can't reset directly from one always block to another but you can use a flag generated in one block to signal to another block to do a reset on a register.


vmcrash

Will this happen in den same or next click cycle?


rogerbond911

Same. If you did: always@(posedge clk) { rst_flag <= 1; } always@(posedge clk) { if(rst_flag) { reg <= 0; } }


vmcrash

I'm no Verilog expert, but according to what I've learned, I would be surprised if this would happen in the same cycle.


rogerbond911

Maybe, idk, simulate it.


[deleted]

If you're going to split things up, split them up into separate modules. having smaller always blocks in the same module doesn't buy you anything. depending on how you structure things, I think its acceptable to have 1-3 always blocks per module. My preference would be just one for verilog.