Hello, my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) reg memory_access; reg[1:0] memory_access_size; always @ (posedge clk) begin if (clk_en && should_decode_input) begin memory_access_size <= 2'bxx; // <--- case(some_input_data) ACTION_1: begin memory_access <= 1; memory_access_size <= 2'b10; end ACTION_2: begin memory_access <= 1; memory_access_size <= 2'b01; end ACTION_3: begin memory_access <= 0; end endcase end end (the actual scenario is a Thumb instruction decoder) My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying "unless I assign a new value to memory_access_size, do whatever with it". Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no longer relevant), presumably reducing the logic complexity. I'm wondering whether this really is the case, in particular: - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? - Does this introduce any caveats to be aware of? - Would you generally consider this a good coding practice? Thanks in advance -M
Explicitly setting a variable to undefined
Started by ●May 25, 2016
Reply by ●May 25, 20162016-05-25
In article <f2fbb4be-84a9-48cc-8210-1c9ef0830ea9@googlegroups.com>, <minexew@gmail.com> wrote:>Hello, >my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) > >reg memory_access; >reg[1:0] memory_access_size; > >always @ (posedge clk) begin > if (clk_en && should_decode_input) begin > memory_access_size <= 2'bxx; // <--- > > case(some_input_data) > ACTION_1: begin > memory_access <= 1; > memory_access_size <= 2'b10; > end > ACTION_2: begin > memory_access <= 1; > memory_access_size <= 2'b01; > end > ACTION_3: begin > memory_access <= 0; > end > endcase > end >end > >(the actual scenario is a Thumb instruction decoder) > >My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying >"unless I assign a new value to memory_access_size, do whatever with it". Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no >longer relevant), presumably reducing the logic complexity. > >I'm wondering whether this really is the case, in particular: >- Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? >- Does this introduce any caveats to be aware of? >- Would you generally consider this a good coding practice?I *AGGRESSIVELY* avoid introducing Xs, and work hard to eliminate ANY sources of X in my design. Goggle search term "X-optimism", and "X-pessimism". Any logic optimization's going to me TINY in the grand scheme of things. The hazards waiting to bite you are not worth it. I'd "eye" optimize it, by just assigning it to one of the other values you've already assigned in the other qualifications. It'll likely come out darn near equivalent. Regards, Mark
Reply by ●May 25, 20162016-05-25
Dne středa 25. května 2016 20:16:39 UTC+2 Mark Curry napsal(a):> In article <f2fbb4be-84a9-48cc-8210-1c9ef0830ea9@googlegroups.com>, > <minexew@gmail.com> wrote: > >Hello, > >my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) > > > >reg memory_access; > >reg[1:0] memory_access_size; > > > >always @ (posedge clk) begin > > if (clk_en && should_decode_input) begin > > memory_access_size <= 2'bxx; // <--- > > > > case(some_input_data) > > ACTION_1: begin > > memory_access <= 1; > > memory_access_size <= 2'b10; > > end > > ACTION_2: begin > > memory_access <= 1; > > memory_access_size <= 2'b01; > > end > > ACTION_3: begin > > memory_access <= 0; > > end > > endcase > > end > >end > > > >(the actual scenario is a Thumb instruction decoder) > > > >My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying > >"unless I assign a new value to memory_access_size, do whatever with it". Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no > >longer relevant), presumably reducing the logic complexity. > > > >I'm wondering whether this really is the case, in particular: > >- Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? > >- Does this introduce any caveats to be aware of? > >- Would you generally consider this a good coding practice? > > I *AGGRESSIVELY* avoid introducing Xs, and work hard to eliminate ANY sources of > X in my design. Goggle search term "X-optimism", and "X-pessimism". > Any logic optimization's going to me TINY in the grand scheme of things. > The hazards waiting to bite you are not worth it. > > I'd "eye" optimize it, by just assigning it to one of the other values > you've already assigned in the other qualifications. It'll likely > come out darn near equivalent. > > Regards, > > MarkIsn't that exactly the point, though? The variable at that point really becomes undefined - and if any other code assumes it to be defined, it is a bug. If the X ends up propagating where it shouldn't, it means there is something wrong with the logic. I'll look into the terms you mentioned. They seem to be what I was looking for, but couldn't find. Thank you, M.
Reply by ●May 25, 20162016-05-25
In article <10bd1028-a05c-45aa-a9db-ed43392e0b14@googlegroups.com>, <minexew@gmail.com> wrote:>Dne středa 25. května 2016 20:16:39 UTC+2 Mark Curry napsal(a): >> In article <f2fbb4be-84a9-48cc-8210-1c9ef0830ea9@googlegroups.com>, >> <minexew@gmail.com> wrote: >> >Hello, >> >my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) >> > >> >reg memory_access; >> >reg[1:0] memory_access_size; >> > >> >always @ (posedge clk) begin >> > if (clk_en && should_decode_input) begin >> > memory_access_size <= 2'bxx; // <--- >> > >> > case(some_input_data) >> > ACTION_1: begin >> > memory_access <= 1; >> > memory_access_size <= 2'b10; >> > end >> > ACTION_2: begin >> > memory_access <= 1; >> > memory_access_size <= 2'b01; >> > end >> > ACTION_3: begin >> > memory_access <= 0; >> > end >> > endcase >> > end >> >end >> > >> >(the actual scenario is a Thumb instruction decoder) >> > >> >My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying >> >"unless I assign a new value to memory_access_size, do whatever with it". Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no >> >longer relevant), presumably reducing the logic complexity. >> > >> >I'm wondering whether this really is the case, in particular: >> >- Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? >> >- Does this introduce any caveats to be aware of? >> >- Would you generally consider this a good coding practice? >> >> I *AGGRESSIVELY* avoid introducing Xs, and work hard to eliminate ANY sources of >> X in my design. Goggle search term "X-optimism", and "X-pessimism". >> Any logic optimization's going to me TINY in the grand scheme of things. >> The hazards waiting to bite you are not worth it. >> >> I'd "eye" optimize it, by just assigning it to one of the other values >> you've already assigned in the other qualifications. It'll likely >> come out darn near equivalent. >> >> Regards, >> >> Mark > >Isn't that exactly the point, though? The variable at that point really becomes undefined > - and if any other code assumes it to be defined, it is a bug. If the X ends up >propagating where it shouldn't, it means there is something wrong with the logic.There's finding bugs and creating the most optimal design. The second goal is way behind the first, IMHO. I'll not introduce X's to get a more optimal design. Ever. As a matter of fact I go extensively out of my way to avoid hidden bugs at sometimes significant costs to Quality of Results. Xilinx likes to preach "Don't reset everything. Reset should be the exception not the rule." My design style is exacty the opposite. Reset everything (to avoid initialization Xs), with some exceptions. I'm of the opinion that Xilinx is hopelessly wrong in this regard, and is advocating wreckless guidance. As to finding bugs, your mileage may vary. I avoid introducing X's. I don't think they buy me anything actually, and may hinder. Read the papers - there's a lot out there. There's no easy answer. Regards, Mark
Reply by ●May 25, 20162016-05-25
On 5/25/2016 2:30 PM, minexew@gmail.com wrote:> Dne středa 25. května 2016 20:16:39 UTC+2 Mark Curry napsal(a): >> In article <f2fbb4be-84a9-48cc-8210-1c9ef0830ea9@googlegroups.com>, >> <minexew@gmail.com> wrote: >>> Hello, >>> my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) >>> >>> reg memory_access; >>> reg[1:0] memory_access_size; >>> >>> always @ (posedge clk) begin >>> if (clk_en && should_decode_input) begin >>> memory_access_size <= 2'bxx; // <--- >>> >>> case(some_input_data) >>> ACTION_1: begin >>> memory_access <= 1; >>> memory_access_size <= 2'b10; >>> end >>> ACTION_2: begin >>> memory_access <= 1; >>> memory_access_size <= 2'b01; >>> end >>> ACTION_3: begin >>> memory_access <= 0; >>> end >>> endcase >>> end >>> end >>> >>> (the actual scenario is a Thumb instruction decoder) >>> >>> My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying >>> "unless I assign a new value to memory_access_size, do whatever with it".. Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no >>> longer relevant), presumably reducing the logic complexity. >>> >>> I'm wondering whether this really is the case, in particular: >>> - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? >>> - Does this introduce any caveats to be aware of? >>> - Would you generally consider this a good coding practice? >> >> I *AGGRESSIVELY* avoid introducing Xs, and work hard to eliminate ANY sources of >> X in my design. Goggle search term "X-optimism", and "X-pessimism". >> Any logic optimization's going to me TINY in the grand scheme of things. >> The hazards waiting to bite you are not worth it. >> >> I'd "eye" optimize it, by just assigning it to one of the other values >> you've already assigned in the other qualifications. It'll likely >> come out darn near equivalent. >> >> Regards, >> >> Mark > > Isn't that exactly the point, though? The variable at that point really becomes undefined - and if any other code assumes it to be defined, it is a bug. If the X ends up propagating where it shouldn't, it means there is something wrong with the logic. > > I'll look into the terms you mentioned. They seem to be what I was looking for, but couldn't find.I'm not sure what you intend. I think you are saying the "some_input_data" can have values other than the defined cases in normal operation. But they should only occur at times the following logic won't care. I would normally say check your input data, but it seems you are allowing undefined states. memory_access_size only takes the values 'b01 or 'b10. I would assign a value of say 'b11 and have the downstream logic check for that. If the downstream logic is using that input when it is in the wrong value it can explicitly throw a flag. Can you define those times easily? -- Rick C
Reply by ●May 25, 20162016-05-25
Dne středa 25. května 2016 20:51:33 UTC+2 rickman napsal(a):> On 5/25/2016 2:30 PM, minexew@gmail.com wrote: > > Dne středa 25. května 2016 20:16:39 UTC+2 Mark Curry napsal(a): > >> In article <f2fbb4be-84a9-48cc-8210-1c9ef0830ea9@googlegroups.com>, > >> <minexew@gmail.com> wrote: > >>> Hello, > >>> my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) > >>> > >>> reg memory_access; > >>> reg[1:0] memory_access_size; > >>> > >>> always @ (posedge clk) begin > >>> if (clk_en && should_decode_input) begin > >>> memory_access_size <= 2'bxx; // <--- > >>> > >>> case(some_input_data) > >>> ACTION_1: begin > >>> memory_access <= 1; > >>> memory_access_size <= 2'b10; > >>> end > >>> ACTION_2: begin > >>> memory_access <= 1; > >>> memory_access_size <= 2'b01; > >>> end > >>> ACTION_3: begin > >>> memory_access <= 0; > >>> end > >>> endcase > >>> end > >>> end > >>> > >>> (the actual scenario is a Thumb instruction decoder) > >>> > >>> My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying > >>> "unless I assign a new value to memory_access_size, do whatever with it".. Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no > >>> longer relevant), presumably reducing the logic complexity. > >>> > >>> I'm wondering whether this really is the case, in particular: > >>> - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? > >>> - Does this introduce any caveats to be aware of? > >>> - Would you generally consider this a good coding practice? > >> > >> I *AGGRESSIVELY* avoid introducing Xs, and work hard to eliminate ANY sources of > >> X in my design. Goggle search term "X-optimism", and "X-pessimism". > >> Any logic optimization's going to me TINY in the grand scheme of things. > >> The hazards waiting to bite you are not worth it. > >> > >> I'd "eye" optimize it, by just assigning it to one of the other values > >> you've already assigned in the other qualifications. It'll likely > >> come out darn near equivalent. > >> > >> Regards, > >> > >> Mark > > > > Isn't that exactly the point, though? The variable at that point really becomes undefined - and if any other code assumes it to be defined, it is a bug. If the X ends up propagating where it shouldn't, it means there is something wrong with the logic. > > > > I'll look into the terms you mentioned. They seem to be what I was looking for, but couldn't find. > > I'm not sure what you intend. I think you are saying the > "some_input_data" can have values other than the defined cases in normal > operation. But they should only occur at times the following logic > won't care. I would normally say check your input data, but it seems > you are allowing undefined states. > > memory_access_size only takes the values 'b01 or 'b10. I would assign a > value of say 'b11 and have the downstream logic check for that. If the > downstream logic is using that input when it is in the wrong value it > can explicitly throw a flag. Can you define those times easily? > > -- > > Rick CMaybe it isn't as obvious as I hoped - in the case of ACTION_3, no memory access will take place and no other code should attempt to make decisions based on this memory access' size (because there isn't any!) Also, from the synthesizer's point of view, the logic for setting memory_access_size should become simpler. I believe, however, that I'm starting to understand one of the deeper problem with X's. I didn't realize that if (1'b1 == 1'bx) will evaluate to false, instead of immediately aborting the simulation with an error, which would be the right thing to do IMO. Of course, it's not as simple as it may seem, because an expression like (1'b0 && 1'bx) is perfectly valid. I'm not even sure if determining the validity of these expressions would be trivial. Now I see how X-values can mask actual errors in the design and I'll probably start to avoid them too. -M.
Reply by ●May 25, 20162016-05-25
On 5/25/2016 3:07 PM, minexew@gmail.com wrote:> Dne středa 25. května 2016 20:51:33 UTC+2 rickman napsal(a): >> On 5/25/2016 2:30 PM, minexew@gmail.com wrote: >>> Dne středa 25. května 2016 20:16:39 UTC+2 Mark Curry napsal(a): >>>> In article <f2fbb4be-84a9-48cc-8210-1c9ef0830ea9@googlegroups.com>, >>>> <minexew@gmail.com> wrote: >>>>> Hello, >>>>> my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) >>>>> >>>>> reg memory_access; >>>>> reg[1:0] memory_access_size; >>>>> >>>>> always @ (posedge clk) begin >>>>> if (clk_en && should_decode_input) begin >>>>> memory_access_size <= 2'bxx; // <--- >>>>> >>>>> case(some_input_data) >>>>> ACTION_1: begin >>>>> memory_access <= 1; >>>>> memory_access_size <= 2'b10; >>>>> end >>>>> ACTION_2: begin >>>>> memory_access <= 1; >>>>> memory_access_size <= 2'b01; >>>>> end >>>>> ACTION_3: begin >>>>> memory_access <= 0; >>>>> end >>>>> endcase >>>>> end >>>>> end >>>>> >>>>> (the actual scenario is a Thumb instruction decoder) >>>>> >>>>> My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying >>>>> "unless I assign a new value to memory_access_size, do whatever with it".. Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no >>>>> longer relevant), presumably reducing the logic complexity. >>>>> >>>>> I'm wondering whether this really is the case, in particular: >>>>> - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? >>>>> - Does this introduce any caveats to be aware of? >>>>> - Would you generally consider this a good coding practice? >>>> >>>> I *AGGRESSIVELY* avoid introducing Xs, and work hard to eliminate ANY sources of >>>> X in my design. Goggle search term "X-optimism", and "X-pessimism". >>>> Any logic optimization's going to me TINY in the grand scheme of things. >>>> The hazards waiting to bite you are not worth it. >>>> >>>> I'd "eye" optimize it, by just assigning it to one of the other values >>>> you've already assigned in the other qualifications. It'll likely >>>> come out darn near equivalent. >>>> >>>> Regards, >>>> >>>> Mark >>> >>> Isn't that exactly the point, though? The variable at that point really becomes undefined - and if any other code assumes it to be defined, it is a bug. If the X ends up propagating where it shouldn't, it means there is something wrong with the logic. >>> >>> I'll look into the terms you mentioned. They seem to be what I was looking for, but couldn't find. >> >> I'm not sure what you intend. I think you are saying the >> "some_input_data" can have values other than the defined cases in normal >> operation. But they should only occur at times the following logic >> won't care. I would normally say check your input data, but it seems >> you are allowing undefined states. >> >> memory_access_size only takes the values 'b01 or 'b10. I would assign a >> value of say 'b11 and have the downstream logic check for that. If the >> downstream logic is using that input when it is in the wrong value it >> can explicitly throw a flag. Can you define those times easily? >> >> -- >> >> Rick C > > Maybe it isn't as obvious as I hoped - in the case of ACTION_3, no memory access will take place and no other code should attempt to make decisions based on this memory access' size (because there isn't any!) > Also, from the synthesizer's point of view, the logic for setting memory_access_size should become simpler. > > I believe, however, that I'm starting to understand one of the deeper problem with X's. I didn't realize that > > if (1'b1 == 1'bx) > > will evaluate to false, instead of immediately aborting the simulation with an error, which would be the right thing to do IMO. > Of course, it's not as simple as it may seem, because an expression like (1'b0 && 1'bx) is perfectly valid. I'm not even sure if determining the validity of these expressions would be trivial. > > Now I see how X-values can mask actual errors in the design and I'll probably start to avoid them too.I'm a bit unclear. In your synthesizable code, you don't have a comparison like this do you? I'm not so familiar with Verilog as I am VHDL. In VHDL they have an assert statement that can throw an error flag. But I think the issue is that there will be logic that uses the memory access size, but when the size is not valid, the logic should not be used. I'm not sure how you would distinguish those two states. That's the issue, is that logic in use when there is no memory access? Why can't you define this in terms of logic and detect it either in your test bench or in the synthesized code? -- Rick C
Reply by ●May 25, 20162016-05-25
On 05/25/2016 10:58 AM, minexew@gmail.com wrote:> Hello, > my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) > > reg memory_access; > reg[1:0] memory_access_size; > > always @ (posedge clk) begin > if (clk_en && should_decode_input) begin > memory_access_size <= 2'bxx; // <--- > > case(some_input_data) > ACTION_1: begin > memory_access <= 1; > memory_access_size <= 2'b10; > end > ACTION_2: begin > memory_access <= 1; > memory_access_size <= 2'b01; > end > ACTION_3: begin > memory_access <= 0; > end > endcase > end > end > > (the actual scenario is a Thumb instruction decoder) > > My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying "unless I assign a new value to memory_access_size, do whatever with it". Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no longer relevant), presumably reducing the logic complexity. > > I'm wondering whether this really is the case, in particular: > - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? > - Does this introduce any caveats to be aware of? > - Would you generally consider this a good coding practice? > > Thanks in advance > -M >Other than the creeping red cancer eating your simulation viewer, I don't think you will get much notice of the X values in a simulation. Stylistically, I would put a default in the case statement. I have seen enough state machines go wrong in unpleasant and difficult to identify ways due to not completely specifying results. I think that a static value would result in the optimization results you want without the risks. Good Luck, BobH
Reply by ●May 25, 20162016-05-25
On Wednesday, May 25, 2016 at 1:58:21 PM UTC-4, min...@gmail.com wrote: <snip>Thus, in the ACTION_3 case, it doesn't have to care about preserving> its previous value (which is no longer relevant), presumably reducing the > logic complexity.That's an assumption. When you go to validate that assumption, I think you'll find that there is no benefit, you'll likely get the exact same output binary file.> > I'm wondering whether this really is the case, in particular: > - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools?No (or at least it didn't used to with Altera). What Quartus would do is replace the don't care (and any other metavalues) with a 0. This gets reported in the transcript window as a note.> - Does this introduce any caveats to be aware of?Not really. If it simulates properly (and it should), then it will work the same in real hardware.> - Would you generally consider this a good coding practice? >Here are some yay/nays - No, because it does not produce any actual benefit. - Yes, if you try it out and find that all of the latest releases of the tools from whoever you would tend to target parts does actually benefit. - Maybe, if you are producing code that is intended for others to use and you have no idea whether the tools that they may use would benefit. In this case though, as long as their is no harm (like the tool erroring out) then it's OK since code that you are providing is typically not meant to be monkeyed around with by the user. Kevin Jennings
Reply by ●May 28, 20162016-05-28
On Wednesday, May 25, 2016 at 8:58:21 PM UTC+3, min...@gmail.com wrote:> Hello, > my question is probably best explained on a piece of code (the snippet is Verilog, but the question should be mostly language-agnostic) > > reg memory_access; > reg[1:0] memory_access_size; > > always @ (posedge clk) begin > if (clk_en && should_decode_input) begin > memory_access_size <= 2'bxx; // <--- > > case(some_input_data) > ACTION_1: begin > memory_access <= 1; > memory_access_size <= 2'b10; > end > ACTION_2: begin > memory_access <= 1; > memory_access_size <= 2'b01; > end > ACTION_3: begin > memory_access <= 0; > end > endcase > end > end > > (the actual scenario is a Thumb instruction decoder) > > My question is about the line marked with "// <---". If I understand the semantics correctly, including this line should make the compiler's job easier, by basically saying "unless I assign a new value to memory_access_size, do whatever with it". Thus, in the ACTION_3 case, it doesn't have to care about preserving its previous value (which is no longer relevant), presumably reducing the logic complexity. > > I'm wondering whether this really is the case, in particular: > - Will this actually lead to more efficient logic realization with generally available (Altera, Xilinx) tools? > - Does this introduce any caveats to be aware of? > - Would you generally consider this a good coding practice? > > Thanks in advance > -MIt could be dangerous for simulation because memory_access_size(0) /= '0' will evaluate to True if memory_access_size(0) = 'U' But I use this in my testbenches assigning DataIn <= x"UUUUUUUU" when DataInValid = '0'. Then I check if DataOut never has 'U' or 'X' when DataOutValid = '1'. That means that I never use data which are not Valid.





