I would like to elaborate further this line of code:
assign out = (!Gbar2A & !Gbar2B & G1)?(255 - (1<<in)):255;
(255 - x) is assuredly going to produce a subtractor (with all of the
borrow logic) when it's not necessary. The synthesizer MAY, after a
lot of analysis, simplify this properly, but why take the risk and do
it this way when it's not what you mean anyhow? To get the same
result, you would want to use something like (255 ^ x), which just
generates a bunch of parallel XOR gates. (This is a special case
where (255-x) and (255^x) give you the same result, but it's an
important special case that you should understand.) Actually, the
synthesizer would figure out that 255 is a constant and turn it into a
bunch of inverters. But since what you wanted in the first place was
inverters anyhow, why not just express that? That would be (~x).
So, let's break this up a little. First of all, you have the enable signal:
assign enable = !Gbar2A & !Gbar2B & G1;
Perfectly good verilog code. (Although I'm a bit bugged by the mixing
of the bitwise | wiht the boolean !, but I think the order of
operations is okay.) However, some examples may need a disable
instead (just depends):
assign disable = Gbar2A || Gbar2B || !G1;
(I use || instead of | because I'm thinking about booleans, but | is okay.)
Next, we have the terniary operator, (x ? y : z). This usually
results in a MUX. At least, that's what the synthesizer is going to
assume. But we're muxing here with a constant, and not just any
constant, but one that's all 1-bits. Depending on how you look at it,
using the terniary may actually make it more readable, even if it
doesn't result in better logic. That's okay. Go for readability.
However, we're not going for readability here. We're going for
terseness that doesn't hurt performance.
To directly replace the MUX, I would suggest that we do this:
assign out = (~(1<<in)) | {8{disable}};
Of course, we still have that shifter. It may or may not produce good
logic for this case. I think I've tested it before, and I think it
was okay. Do what you think makes sense semantically. Are we really
doing a shift here? I don't think so. Rather, this is what a
software engineer would do to get the result in C. That doesn't mean
it's a bad trick for Verilog, but you have to be careful to not let
your software background bite you.
As one final change to make this more terse, I suggest this:
assign out = ~(enable << in);
There is a concern, however, that Verilog will see that enable is one
bit and give you a 1-bit result. There complexities of "natural size"
are greater than I want to try to explain here, and I don't remember
them well enough anyhow. Suffice it to say that if enable were 8 bits
or the ~ operator were not there, you'd get what you expect. However,
in this case, I don't think you will. There are a couple of
solutions. One is this:
assign out = ~({7'b0, enable} << in);
Another is:
wire [7:0] shifted = enable << in;
assign out = ~shifted;
Of course, for all of this, your terseness completely goes out the window.
Note that the above example:
assign out = (~(1<<in)) | {8{disable}};
... would actually work! And that's because an undecorated integer
constant's default "type" is a signed 32-bit integer. It would only
break if you were trying to deal with something larger than 32 bits.
And watch out if you do, because when dealing with 64-bit words, I've
had this bite me before!
So, you should be getting the message by now: Attempts to "optmize"
at a syntactic level are only making things harder. When you do that,
you run into pitfall after pitfall. The solution is to stick to
simple, direct expressions that are verbose and clear.
--
Timothy Normand Miller
http://www.cse.ohio-state.edu/~millerti
Open Graphics Project
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)