Is this "legal" in Verilog? - Page 1
Forum section: electronics / general

author: betocool
author_rank: Regular Contributor
timestamp: February 06, 2022, 11:23:06 pm
content: Hi all, I have this bit of code that runs ok when I simulate it with Verilator. However, I'm having issues compiling it with Symbiflow... so maybe it's a case of "oh... you're not allowed to do that" sort of thing. I'm not very fluent in Verilog, more of a VHDL person, but trying things out at the moment:Code:always @(posedge clk) beginif(!resetn) begincfg_reg <= 32'h 0000_0000;presc_reg <= 32'h 0000_0000;cnt_reg <= 32'h 0000_0000;presc_cnt <= 32'h 0000_0000;end else beginif (reg_we != 4'b 0000) begincase(reg_addr)4'b 0000: cfg_reg <= reg_di;4'b 0001: presc_reg <= reg_di;4'b 0010: cnt_reg <= reg_di;endcasewr_ready <= 1;end else beginwr_ready <= 0;endif(cfg_reg == 32'h 0000_0001) beginif (presc_cnt == presc_reg) beginpresc_cnt <= 0;end else beginpresc_cnt <= presc_cnt + 1;endif(presc_reg == 0) begincnt_reg <= cnt_reg + 1;end else beginif (presc_reg == presc_cnt) begincnt_reg <= cnt_reg + 1;endendendendendThe question is regarding if I can use a "case" statement within a clocked process... Like I said, Verilator accepts it...Cheers,Alberto

author: Bassman59
author_rank: Super Contributor
timestamp: February 06, 2022, 11:26:05 pm
content: Of course you can use a case within a clocked block!Symbiflow's parser may be confused. It wouldn't be the first time that a front-end parser chokes on legal language structures.

author: Someone
author_rank: Super Contributor
timestamp: February 07, 2022, 01:04:38 am
content: Things in that code making it harder for the tools:if/else reset (avoid resets for FPGA targets)case statement inside a wrapping if, nothing on the elsepartial decode/no default caseIts all "legal" but can lead to sub optimal results.Given what you are doing in that case statement, it would be cleaner for the tools to have them as 3 discrete if statements.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 07, 2022, 01:48:11 am
content: Quote from: betocool on February 06, 2022, 11:23:06 pmMaybe you could tell us what the issues are.

author: Cerebus
author_rank: Super Contributor
timestamp: February 07, 2022, 05:09:41 am
content: If we take out all the unecessary begin..end blocks wrapped around single statements the code becomes a lot clearer and we can actually see it.Code:always @(posedge clk) beginif(!resetn) begincfg_reg <= 32'h 0000_0000;presc_reg <= 32'h 0000_0000;cnt_reg <= 32'h 0000_0000;presc_cnt <= 32'h 0000_0000;endelsebeginif (reg_we != 4'b 0000)begincase(reg_addr)4'b 0000: cfg_reg <= reg_di;4'b 0001: presc_reg <= reg_di;4'b 0010: cnt_reg <= reg_di;endcasewr_ready <= 1;endelsewr_ready <= 0;if(cfg_reg == 32'h 0000_0001)beginif (presc_cnt == presc_reg)presc_cnt <= 0;elsepresc_cnt <= presc_cnt + 1;if(presc_reg == 0)cnt_reg <= cnt_reg + 1;elseif (presc_reg == presc_cnt)cnt_reg <= cnt_reg + 1;endendendThen it become obvious where two problems are:Code:if (presc_cnt == presc_reg)presc_cnt <= 0;elsepresc_cnt <= presc_cnt + 1;if(presc_reg == 0)cnt_reg <= cnt_reg + 1;elseif (presc_reg == presc_cnt)cnt_reg <= cnt_reg + 1;You need to factor out the redundant tests on the same conditionif (presc_cnt == presc_reg)versusif (presc_reg == presc_cnt)- which is the same condition expressed backwards - and the redundant assignments ofcnt_reg <= cnt_reg + 1;on both arms of the final if. So restructuring the final if that becomes:Code:if (presc_cnt == presc_reg)presc_cnt <= 0;elsepresc_cnt <= presc_cnt + 1;if((presc_reg == 0) | (presc_cnt == presc_reg))cnt_reg <= cnt_reg + 1;Which still leaves that double condition check there. It might be right, I haven't reverse engineered what your logic might be intended to be, but it has the feel of a "bad code smell" to me.Myguessat your intended logic suggests that what you wanted to write was:Code:if((presc_reg == 0) | (presc_reg == presc_cnt)) // If the prescale factor is set to zero, or the prescale counter has hit the scale countbegincnt_reg <= cnt_reg + 1; // Increment the actual counterpresc_cnt <= 0; // Clear the prescaler counterendelsepresc_cnt <= presc_cnt + 1; // Increment the prescaler counterYou still have problems left, because there are two places, that can execute simultaneously, thatbothtry to write tocnt_reg, the block that executes if(reg_we != 4'b 0000)and the block that executes if(cfg_reg == 32'h 0000_0001). Simulation will let you do that, synthesis won't. You need to make those two blocks mutually exclusive. Youwillhave got an error message about the clash of assignments, it would have made things a lot easier if you'd included it rather than just handwaving 'so maybe it's a case of "oh... you're not allowed to do that" sort of thing'.You also probably want to movewr_readyinto your reset block rather than leaving it undefined until after the first execution of theif(reg_we != 4'b 0000)block.

author: asmi
author_rank: Super Contributor
timestamp: February 07, 2022, 06:51:53 am
content: Quote from: Cerebus on February 07, 2022, 05:09:41 amWe've just had a discussion on this in another thread. Multiple assignments within a single always_* block are not only allowed, but such behavior is explicitly defined in the specification, namely, the last assignment in the code flow always wins, and so there is never a clash nor any ambiguity. This is very convenient in many cases for state machines, when you can assign "default" values in the beginning of the block, and later down the flow only reassign those signals which are supposed to have non-default values.

author: Cerebus
author_rank: Super Contributor
timestamp: February 07, 2022, 08:57:38 am
content: Quote from: asmi on February 07, 2022, 06:51:53 amMy own experience has been that if you pile a load of defaults at the top an always there's no problem, the tools can figure out what you mean - in fact I typically do just that for the outputs from state machines. If your conflicting drivers are buried away behind a couple of conditionals that could both be true all hell breaks loose, well OK, you get an error message. Imagine it as "How would I build this physically out of multiplexers without using priority encoders" and you find you can't. If there's anything in there that looks like a priority encoder (e.g. nested ifs) then it sails through. it's only when it can't work out "who wins" on two simultaneous enables that it breaks, and although the standards might say that the lexically latest wins, some of the tools don't seem to have got that message.Edit: Out of curiosity I went away and tested this out in Yosys on as simple a test case as I could.Code:module Test (input wire clk,input wire enableA,input wire sourceA,input wire enableB,input wire sourceB);reg destination;always @(posedge clk)beginif (enableA) destination <= sourceA;if (enableB) destination <= sourceB;endendmoduleAnd I find to my surprise that itdoesn'tbarf on it, and it superficially appears acts according to standards. I have definitely had problems with this in the past, but with exactlywhichsynthesis engine I'm not now sure. I thought I had encountered it in Yosys, so either Yosys has changed or it was another tool, but either way my technical objection fails.Presumably to do this Yosys has to synthesise a priority encoder. Checking exactly what itdoessynthesise is a job for another time, and when I've got a bit I'll come back to it and take a look.So, I have to remove my objection to clashing sources ontechnicalgrounds, but I'm going to retain my objection on the grounds that code that relies on implicit subtleties is bad compared to code that explicitly states what will happen. That isCode:always @(posedge clk)beginif (enableA) destination <= sourceA;if (enableB) destination <= sourceB;endandCode:always @(posedge clk)beginif (enableB) destination <= sourceB;elseif (enableA) destination <= sourceA;endought to both do exactly the same thing, but the latter makes the coder's intention entirely clear, the former does noteven though it will result in exactly the same behaviour.2nd edit:Here's what gets synthesised by Yosys without any optimisation, two cascaded multiplexers:

author: betocool
author_rank: Regular Contributor
timestamp: February 07, 2022, 12:28:27 pm
content: Hey all, thanks for the answers, it's getting a bit clearer now.To the background, I've dabbled in FPGA's on and off since 2002, more off than on to be honest, and I'm giving Symbiflow a crack, as it seems like a good open source alternative. I mostly worked in VHDL, but Symbiflow only supports Verilog, so I'm kind of getting back to it. I could not for the life of me remember if the statement I asked about was "legal" or "formal'. Unfortunately I did not have any more information about the error message other than:Code:Error 1:Type: Blif fileFile: top.eblifLine: 43998Message: Failed to find matching architecture model for 'LDCE'from the "symbiflow_pack" tool, that's why I didn't post a message with the question.And fair enough, I didn't notice the problems with the same condition in two places, thanks for pointing that out.I will now get my head around the "latches are bad" or "why some latches are bad" issue.Cheers,Alberto

author: AndyC_772
author_rank: Super Contributor
timestamp: February 07, 2022, 01:10:10 pm
content: Quote from: Cerebus on February 07, 2022, 08:57:38 amI'm a little surprised there's any ambiguity here at all; if code doesn't have an explicit, well defined meaning (however difficult for a human being to follow), then that's a major problem.I use VHDL, and often structure code along the following lines. Suppose, for example, that a block of logic is used to perform a sequence of actions that occasionally yield a result that must be kept. That result is pushed into a FIFO, which is triggered by a signal 'fifo_we' having the value '1'.Code:fifo_we <= '0';case state_variable iswhen state_idle =><wait>when state_busy =><do stuff>when state_finished =>fifo_data <= intermediate_result;fifo_we <= '1';end case;if reset_signal = '1' thenfifo_we <= '0';state_variable <= state_idle;end if;There could be very many states depending on the complexity of the system. Most don't generate a final result, so assigning a value to fifo_we in every state would be pointless clutter and repetition, and a potential source of errors (eg. what if one of the states fails to assign a value at all, then it takes the value it had last time round the loop, which was probably zero but not always).Finally, we have a reset condition. In the reset condition, any work in progress is aborted and any result generated should be discarded. Putting this assignment at the end of the loop clearly, unambiguously indicates what changes should occur when a reset is asserted, without the need to test for the reset condition in every state individually. Again, by understanding the way the language is parsed, and the order in which assignments take priority over each other, we've achieved clarity, readability, and a reduced chance of error.

author: asmi
author_rank: Super Contributor
timestamp: February 07, 2022, 02:35:41 pm
content: Quote from: Cerebus on February 07, 2022, 08:57:38 amCan you please give us an example of a tool which does that? And what's the error message?In all the time I used Verilog I have NEVER seen any issues with that, nor did I ever expect to as - like I said - this situation is covered in the standard.

author: asmi
author_rank: Super Contributor
timestamp: February 07, 2022, 02:36:28 pm
content: Quote from: AndyC_772 on February 07, 2022, 01:10:10 pmThere is no ambiguity at all, it's all defined by the standard.

author: Bassman59
author_rank: Super Contributor
timestamp: February 07, 2022, 03:32:53 pm
content: Quote from: Someone on February 07, 2022, 01:04:38 amWhy avoid resets? In some fabrics, an async reset (released synchronously) is required as the configuration mechanism doesn't ensure that registers have a defined initial state.QuoteIf the process is synchronous, an else is not necessary -- the flip-flops will retain their current value if you do not assign to them.

author: Cerebus
author_rank: Super Contributor
timestamp: February 07, 2022, 05:31:01 pm
content: Quote from: asmi on February 07, 2022, 02:35:41 pmSee my edit above.

author: free_electron
author_rank: Super Contributor
timestamp: February 07, 2022, 06:23:02 pm
content: Quote from: asmi on February 07, 2022, 02:36:28 pmcorrect. this is called scheduled logic. you can do this in vhdl too.the root of this lies in the way synthesizers build logic. any 'IF' clause is nothing but a switch (multiplexer) which is pure combinatorial logic. Combinatorial logic can be minimized.an example :build me a counter then can reset, clear , preset to9 , parallel load , count up and down and has an enable.RESET : set counter to 0PRESET: set counter to 9LOAD : load inputENABLE : enable counting and only counting. reset,load preset are not affected by thisUPDOWN : if high : count up , else count down.Code:always_ff @(posedge clk) begincnt <=cnt; // not strictly necessary ...if ENABLE begin // if we are enabledcnt <= cnt-1; // we count downif UPDOWN cnt <=cnt+1; //unless UPDOWN is high , in which case we count up.endif (LOAD) cnt <input; // if load is high we parallel load.if (PRESET) cnt <=9; // you get the idea by now.if (RESET) cnt<0;endthe attached image shows the decision logic being built. anything before the actual register ( flipflops) is purely combinatorial and can be minimized with very high efficiency. ( in an FPGA this gets converted into a LUT whereas in true silicon this becomes a logic cloud. )Note that the adder/subtractor can actually get implemented as a rom ( if this is a 4 bit counter this becomes a simple look back/ahead mux )

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 07, 2022, 07:29:26 pm
content: Quote from: betocool on February 07, 2022, 12:28:27 pmMaybe you could have also told us what was the target FPGA? (Unless I missed it.)The 'LDCE' primitive is a "Transparent Data Latch with Asynchronous Clear and Gate Enable" (Xilinx). It can be found in various forms and names on various FPGAs. Possibly some FPGAs do not support that, but that would sound odd.While latches should be avoided in general in synchronous designs (and yes, that can be fixed on a RTL level), they can usually be implemented in many FPGAs, so the message you get from Symbiflow is a bit odd. So, could you tell us what your target is? And maybe you have incorrectly defined the target when running the toolchain? We need more info. (But sure, getting rid of latches in your code should "fix" this, just saying that maybe this error message is revealing yet another issue in your setup.)

author: asmi
author_rank: Super Contributor
timestamp: February 07, 2022, 07:41:59 pm
content: Quote from: Cerebus on February 07, 2022, 05:31:01 pmSo there is nothing aside from subjective opinions regarding code style. Which is what I suspected in the first place.BTW, in SystemVerilog you can enforce checking for uniquiness of if/else and case conditions byt employing "unique" qualifier ("unique if" or "unique case"). This will display a warning if synthesizer/simulator will determine that those conditions are in fact not mutually-exclusive. More importantly, it will remove any priority encoding logic which might normally be there as it makes no sense when all conditions are exclusive and so exactly one of them is true at any point of time, which can lead to lower resource utilization and higher Fmax.

author: Cerebus
author_rank: Super Contributor
timestamp: February 07, 2022, 08:35:05 pm
content: Quote from: asmi on February 07, 2022, 07:41:59 pmHave you ever considered answering in these types of topics by trying to be helpful to the OP rather than going around being adversarial to everybody who is trying to help?

author: asmi
author_rank: Super Contributor
timestamp: February 07, 2022, 09:14:24 pm
content: Quote from: Cerebus on February 07, 2022, 08:35:05 pmI'm not adversarial to anybody, I'm simply pointing out factual errors whenever I notice them. That's all there is to it.It's important to differentiate opinions from facts, and avoid representing the former as the latter. Opinions can be debated and are often subjective and preferential, but facts are just what they are, and the concept of right and wrong applies to them. This is especially so when talking to beginners because they lack knowledge and experience to tell them apart.

author: Cerebus
author_rank: Super Contributor
timestamp: February 07, 2022, 09:54:11 pm
content: Quote from: asmi on February 07, 2022, 09:14:24 pmIt's a matter of tone. If someone goes and updates a post to correct themselves it is both unnecessary and confrontational to follow that up with the equivalent of "Told you so". That's not about the facts, it's not even debating opinion, it's just chest thumping.

author: asmi
author_rank: Super Contributor
timestamp: February 07, 2022, 10:05:16 pm
content: Quote from: Cerebus on February 07, 2022, 09:54:11 pmThat's not what I meant, but - OK - I will try to do better to avoid misunderstandings in the future. Let's leave it at that.

author: betocool
author_rank: Regular Contributor
timestamp: February 07, 2022, 11:11:44 pm
content: QuoteSorry, yes, it's an Artix 7 board. The toolchain definitions were OK, I tested this board on other examples and it works fine. The definitions are from a common makefile, so that doesn't change.The folks at the symbiflow chat also told me about removing the latches, so I changed the code into different sections for each register that holds data or a counter (by the way, this is a simple counter for a picosoc RV5 I'm trying things on). It generated the bitstream correctly, simulation worked, and the compiled firmware worked too. Thanks for all the input.Code:always @(posedge clk) beginif((!resetn) || (presc_reg == 32'h 0000_0000))presc_cnt <= 32'h 0000_0000;presc_clk <= 0;elseif(presc_cnt == presc_reg)presc_cnt <= 32'h 0000_0000;presc_clk <= 1;elsepresc_cnt <= presc_cnt + 1;presc_clk <= 0;endendendassign cnt_clk = (presc_reg == 0) ? clk : presc_clk;always @(posedge cnt_clk) beginif(!resetn) begincnt_reg <= 32'h 0000_0000;cnt_wr_ready <= 0;elseif((reg_we != 4'b 0000) && (reg_addr == 4'b 0010))cnt_reg <= reg_di;cnt_wr_ready <= 1;elseif(cfg_reg == 1)cnt_reg <= cnt_reg + 1;endcnt_wr_ready <= 0;endendendOk, here's another question, something I wasn't aware of. Do I understand correctly that here:Code:cnt <= cnt-1; // we count downif UPDOWN cnt <=cnt+1; //unless UPDOWN is high , in which case we count up.the "if" statement takes precedence (preference?) over the statement above?Cheers,Alberto

author: free_electron
author_rank: Super Contributor
timestamp: February 07, 2022, 11:31:03 pm
content: Quote from: betocool on February 07, 2022, 11:11:44 pmit is not because it is an 'if' statement. it's because it sits lower in the begin-end block."statements shall be executed in the order given". since it sits closer to the 'exit' it has priority. Like i explained : the synthesizer builds logic as it reads statements (in the order given)counter <= counter; : the synthesizer makes a register and wires the output to the input.if (ENABLED) counter <= counter +1; : the synthesizer detached what was already connected to the input of the register , injects a mux under control of 'ENABLE'. what was attached goes to the '0' state of the mux , the new clause is attached to the '1' stateif(RESET) counter <=0; : synthesizer detaches again and does the mux thing again

author: Bassman59
author_rank: Super Contributor
timestamp: February 08, 2022, 12:11:27 am
content: Quote from: betocool on February 07, 2022, 11:11:44 pmThe thing to remember, and it's been said in this thread a few times, is that in an always block, the statements are evaluated in the order you typed them, and the last assignment to any left-hand-side signal wins.So in this example, first you see the down counter, and then you are asked "is UPDOWN true?" and if so, then the up-counter statement is evaluated.This is the equivalent ofCode:if UPDOWNcnt <= cnt + 1;elsecnt <= cnt - 1;and the tools (synthesis, simulation) are smart enough to do the right thing.Which idiom should you use? I always opt for the one which is more obvious to the casual reader. I really don't like to use "tricks."

author: free_electron
author_rank: Super Contributor
timestamp: February 08, 2022, 12:50:57 am
content: Quote from: Bassman59 on February 08, 2022, 12:11:27 amThese are not tricks. it is part of the language definition.If you are making complex logic this method makes things a lot easier. Nested if-then-else spaghetti can be very difficult to read and even more complicated to modify afterwards."oh we wanted preset to work only during enable and parallel load should have precedence over reset..."Simply move the lines of code.when reading such code you can build the functionality in your mind. Precedence is very clear. ( if it comes earlier it is lower)there are other advantages :no hidden or missing pathways/conditions. no risk of latch inferring. less logic, guaranteed clock dependence, no asynchronous stuff

author: Someone
author_rank: Super Contributor
timestamp: February 08, 2022, 01:23:46 am
content: Quote from: Bassman59 on February 07, 2022, 03:32:53 pmSo use a reset if youneedone! If you dont need one then dont use one as its just a waste of time and resources. The particular example the OP posted is a register interface endpoint, exactly the sort of situation where a cargo-cult "reset everything" is unlikely required or desirable. Way too many code snippets just include (global) resets when they are rarely needed.But if you do use a reset, don't use an if/else block unless you want to maintain piles of redundant cases. People further into the thread start discussing these finer points.Quote from: Bassman59 on February 07, 2022, 03:32:53 pmThey sure will, but again why pick such a convoluted control process if its only going to make reading it harder, and the tools will have a harder time putting it together? Not everything ends up as muxes as the above posters are suggesting, the same functionality can be from register enables. As I said, its all permissible and functional but not the clearest way to do things. So whats your point?

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 08, 2022, 03:38:00 am
content: Quote from: betocool on February 07, 2022, 11:11:44 pmOK, so possibly this is a Symbiflow "shortcoming" here. (Even though, as said earlier, removing the latches is actually a good thing here, but just to say that the tools should probably have synthesized this for your FPGA target, so I guess this is a shortcoming or a bug...)

author: Someone
author_rank: Super Contributor
timestamp: February 08, 2022, 04:49:04 am
content: Quote from: SiliconWizard on February 08, 2022, 03:38:00 amWith everything inside a @(posedge clk) is inferring latches anything other than a bug in the tool?

author: Bassman59
author_rank: Super Contributor
timestamp: February 08, 2022, 04:54:24 am
content: Quote from: Someone on February 08, 2022, 01:23:46 amIt's not a cargo cult. I well understand where resets are needed -- like for a state machine -- and where they are not, like in pipelined logic.But whatever. Synplify Pro loves to complain about "Bad things happening" if you don't include a reset in Microsemichip ProASIC-3E, PolarFire, and on the Lattice side in MachXO2. These resets are async, but of course we release them synchronous to the relevant clocks.QuoteI understand -- in the Xilinx world, reset are not necessary because of how the flip-flops' initial states are determined by initializers in the HDL, and when GSR is released, the states of all of the registers are known. Other architectures don't work that way, so we have to use resets.Quote from: SomeoneWhat's interesting is that the advice Someone gives is at cross purposes with the advice others give.I think we can all agree that there's no need for the "else" in this block:Code:always @(posedge clk) beginif (some_logic_is_true)q <= d;elseq <= q;endand that was my point.

author: betocool
author_rank: Regular Contributor
timestamp: February 08, 2022, 07:07:27 am
content: Quote from: free_electron on February 07, 2022, 11:31:03 pmWhat software are you using for your graphs? I'm looking for something that looks like that...Cheers,Alberto

author: Someone
author_rank: Super Contributor
timestamp: February 08, 2022, 08:59:12 am
content: Quote from: Bassman59 on February 08, 2022, 04:54:24 amIts exactly that sort of blanket statement, that people mis-interpret and produce cargo cult resets from. Some state machines might need a reset, but its not something that every state machine needs. Resets that are essential for some specification/functionality are all well and good, but most are just added "because".

author: betocool
author_rank: Regular Contributor
timestamp: February 08, 2022, 01:24:58 pm
content: Alright, just for the sake of the discussion, I replaced this (#1):Code:always @(posedge clk) beginif(!resetn) begincfg_reg <= 32'h 0000_0000;cfg_wr_ready <= 0;end else beginif((reg_we != 4'b 0000) && (reg_addr == 4'b 0000)) begincfg_reg <= reg_di;cfg_wr_ready <= 1;end else begincfg_wr_ready <= 0;endendendwith this (#2):Code:always @(posedge clk) begincfg_wr_ready <= 0;cfg_reg <= cfg_reg; // This does look a bit funky...if((reg_we != 4'b 0000) && (reg_addr == 4'b 0000)) begincfg_reg <= reg_di;cfg_wr_ready <= 1;endif(!resetn) begincfg_reg <= 32'h 0000_0000;cfg_wr_ready <= 0;endendBased on the "last statement wins" this is the order of priority I'd think of, and both ways generate a bitstream and work just fine (simulation and real)... I assume they are technically the same? I still find the "something <= something" statement a bit unsettling... must be because I haven't done this in a while...Not considering whether the "reset" MUST be there or not (let's say yes... for now)... is one way or the other "better" (that is very subjective, I know), or what is considered better practice?Cheers,Alberto

author: Bassman59
author_rank: Super Contributor
timestamp: February 08, 2022, 04:58:38 pm
content: Quote from: betocool on February 08, 2022, 01:24:58 pmI won't answer the "better practice" question, because I think there are too many opinions about this.But in your second block, the assignmentcfg_reg <= cfg_reg;is not needed because the flip-flops hold their state unless there's a new assignment. Also the code describescfg_wr_readyas a one-shot strobe, asserted for only one clock tick, which is reasonable.cfg_reg, assigned a new value at the same time, will hold that new value until the next time that register is addressed. There is no reason to clear it after each register write finishes, right?Regarding "flip-flops hold their state unless assigned," let's discuss that for a moment. On every tick of the clock, the output of the flip-flop updates. It might not change state, but it updates.The basic flip-flop has two synchronous inputs (ignoring the synchronous preset or clear). These inputs are the D (data) input, which is obvious, and the CE (clock enable) input. The CE controls whether what is on the D input appears on the Q output, or whether the previous output continues to drive. It's called a clock enable because once upon a time (and still, in certain cases), the input literally gated the clock. If CE was off, then the flop never saw the clock pulse, so the output would not change. FPGA flops have a "recirculating mux" built in. This is exactly what it says on the tin. The D input feeds one input to that mux, the flop's Q output feeds the other input, and the CE chooses which to clock into the flop. CE = 1 usually means D input.The logic that drives the CE input is connected to CLB resources, just like the D input, so the logic equations that drive the CE input can be pretty complex. This is why when you code something you might thinks is an obvious CE, the synthesis can do something which results in the same behavior but with a different implementation.For yourcfg_regassignment then, you might expect the synthesizer to build a CE that is asserted true when((reg_we != 4'b 0000) && (reg_addr == 4'b 0000))is true, which allows the values onreg_dito update the flops. When that write enable/address compare result is false, the CE is off socfg_regdoesn't change because the old value is fed back into the flop.I didn't forget the synchronous preset and clear! The synthesis tool will use them, if they exist in your fabric (!), if any of your logic describes something that obviously sets or resets a flip-flop. You might see some complex logic driving the PRE or CLR signals in the same way you see it driving D or CE. Now, this is separate from the global reset. Yourif(!resetn)statement should invoke the global reset assumingresetnis "global" in scope.The crux here is that the synthesis tool will build logic out of the available resources to implement what you describe. The result should match what you get when you simulate your design. This is really all that matters, right? The logic generated may be "inefficient" or it might be clever. You really don't care until you don't meet timing constraints or you run out of resources. That's when you start looking into what the synthesis tool generated.Good luck.

author: free_electron
author_rank: Super Contributor
timestamp: February 08, 2022, 06:27:11 pm
content: Quote from: betocool on February 08, 2022, 07:07:27 amPlace- Drawing Tools - LinePlace- Drawing Tools - textPlace- Drawing Tools - circlein altium schematicThe nice thing is : it comes in as vectors when you copy-paste. so i can drop it in inkscape or adobe illustrator and 'massage' at will.

author: free_electron
author_rank: Super Contributor
timestamp: February 08, 2022, 06:56:35 pm
content: Quote from: Bassman59 on February 08, 2022, 04:58:38 pmbe careful with that ...Synthesizers build a fully minimized system first. Then they 'unroll' it to map it on the target architecture.In the old altera tools ( Quartus 9.2 is the latest version i regularly used) you could see the post synthesis schematic. That always had simple d registers that had no reset or preset. only d,q and clk . Then you could also visualize the mapped logic that showed the actual implementation on your target. There you could see what features of the actual flipflops were used. depending on what family you used this schematic changed (and became unreadable for humans). the 'simple' post synthesis was actually what the logic 'does' as opposed ot how it is implemented.That's why you find in the xilinx or altera tools directives that are not true verilog or vhdl. they are there to direct their synthesizer. a lot of the altera macro functions have AHDL ( altera hardware description language) pre-processors to fine control the synthesizer. they use the equivalent of ifdefs to alter implementation depending on family targeted) . Xilinx does that too.If you use Synopsis that all goes out the window. You get raw gates. If you need a 7 input or gate , that is what you get. In the fpga tools that ends up being mapped on two LUTs since there is no such thing as a 7 input or gate. It needs to be built out of three or four 3-input ors. The problem ? Race conditions or speed. Cascading more gates may mean longer accumulated flight time but with constant delays. Doing the second implementations may mean you get glitches and managing setup and hold times is more tricky as signals arrive skewed. That's why FPGAs use LUTS. the time of a signal through a LUT is constant irrespective of how many inputs and outputs are used. In hard logic that problem does not exist. If you need a 23 input and gate the library will have that as it is geometrically smaller than a chain of ands and you can still run at fmax of the silicon. This is one of the reasons FPGAs are invariably slower than actual silicon. They need to 'expand' logic to fit the resources. it is not 'smallest possible' implementationsee diagram

author: betocool
author_rank: Regular Contributor
timestamp: February 08, 2022, 11:00:21 pm
content: Ha ha ha! I thought it was some automated schematic generator or something...Cheers,Alberto