Not much compared to the "norm" around here, but...
15 years ago
Not much compared to the "norm" around here, but...
Neat. Some great things grow from small beginnings.
Here's what I've been hacking on:
I remember seeing the thread in s.e.d. :)
To enhance readability a bit, I would keep the BCD value as a 10 bit vector, rather than split it up between the 3 digits.
In bcd.v, you can then write your case statement as:
case (ibin) 0 : bcd = 10'h0; 1 : bcd = 10'h1; 2 : bcd = 10'h2; 3 : bcd = 10'h3;
...255 : bcd = 10'h255; endcase
In top.v, extract the individual digits for further processing:
wire [1:0] bcd2 = bcd[9:8]; wire [3:0] bcd1 = bcd[7:4]; wire [3:0] bcd0 = bcd[3:0];
Don't worry about the norm. Keep a clarity of exposition in your code and you'll soon overtake most other engineers (who often can't communicate their work clearly after 20-30 years).
"I still think people could be documenting what they write much better" (Knuth, 1996)
I would have tried a 256 way case converting directly from 8 bit binary to16 segments including the leading zero blanking function. Effectively expressing the ROM solution in verilog.
Let the synthesiser do the work. I don't know how 'big' the result would be but you might be pleasantly surprised.
Also it might be more efficient to latch the segment outputs not the binary inputs (at the expense of a little extra data hold time). The macro cells driving the segments have flip flops which are otherwise unused.
I also noticed you are outputting oz for blanking, that probably takes more logic that forcing inactive for blanking.
Neat trick, thanks. I use a perl script to generate the big tables anyway, so readability wasn't high on my list.
I started with that, but consider the blanking, lzblanking, and inverting - that's a 2048 way case. Plus, I wouldn't have had reusable BCD and 7segment modules left over ;-)
I found that the size of the result was somewhat independent of the way I expressed the logic (I tried a LOT of ways trying to fit it into the '36). So I might as well go with something that's readable, editable, and reusable.
That keeps you from using the blanking signal as a PWM brightness control, or the polarity signal to drive LCDs.
I figured since the output drivers had unused enables already, it would just hook into those, saving some gates.
Aughhh! Isn't there a better way to do the binary to BCD conversion? Not that there'd be any difference in performance or area, just that the brute-force enumeration of all possible states seems ugly. I'd hate to do this for a 12-bit or wider conversion.
A 256x10 ROM is pretty clean if it implements in a BlockRAM. If it goes to distributed logic, I'd suggest a Binary to BCD conversion such as that covered inotes/xapp029.pdf (a reasonably-sized url - WooHoo!) coauthored back around `97 by our own Peter Alfke. In those days I was just starting to venture out from the schematic realm into HDLs.
I used the app note to get my head around the simpler conversion technique that I ended up implementing as a function in a picoBlaze LCD display driver recently. Clean.
Perhaps using the Divide and Modulus operators ?
It was pointed out elsewhere that it can be done like this:214 : bcd
Don't try it. XST will complain that the second operand of DIV and MOD operators have to be powers of two, atleast, in the webpack version.
I ran your code and the below code through the Cadence HDL-ICE synthesizer. (For Emulation only) The case statement was mapped to 188 cells in thier library, the DIV/MOD mapped to 92 cells. (AND02,OR02,XOR02,INV,etc.)
But since this code doesn't work in the free ISE it doesn't matter.
module bcd(ibin, bcd2,bcd1,bcd0);
input [7:0] ibin; output[3:0] bcd2, bcd1, bcd0;
wire [7 : 0] temp [0:1];
assign temp = ibin/4'd10; assign bcd0 = ibin%4'd10; assign temp= temp/4'd10; assign bcd1 = temp%4'd10; assign bcd2 = temp%4'd10;
This is static logic, each output is defined by a logical equation containing inputs. Regardless of how you express it in HDL the equations are the same and the synthesiser should minimise and fit them just the same.
Shitty that your synthesiser didn't, assuming you really did express the same thing in different ways.
If you can do this, then you can write it in a loop in about 4 lines! (Either Verilog or VHDL)
Sounds interesting. Can you elaborate ?
Not true! How you describe the logic in HDL greatly influences the gate resources. Yes the two implementations will function identically. I have verified this with random vectors and assertions. Both implementations behave the same. The difference comes when you map to gates. The case statement In theory should produce a fast result at the expenses of how the number of gates. Where as the div/mod version makes use of cascading to reduce the logic at the expense of speed.
It is the same with descriptions of n-bit adders. You can code it with a+b, and let the Synthesizer do what ever it wants. Or you can describe the final layout type explicitly. Example: You need lower gate count and don't care about speed. You would cascade the full-adders giving you n*(2 gate delay), If you want speed but don't care about gates you code a Carry-Look ahead adder where the delay is fixed at (6 gate delay) but the logic gate count grows exponentially.
Synthesizers do not take the final functionality and map the logic the same way. They can do that with the right switches. But by default they will look at your coding style to determine the way to map the logic.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.