Do you have a question? Post it now! No Registration Necessary

Re: binary to BCD assistance

internally
the
I
OK, it did come through but I was looking in the wrong place. Still, it is
often easier just to include it.
I am much better at reading verilog than VHDL, but it doesn't look right to
me. Though I think I don't understand the algorithm, I think it needs to be
more complicated than that, though if you do an iterative algorithm it might
not be so hard. How many clock cycles does it take to get the data from
input to output? How many different values did you put through the
simulator in testing?
-- glen

Re: binary to BCD assistance

sure
The
Start
greater
representation.
As I said, I read Verilog much better than VHDL. I didn't even notice the
loop yesterday, which is why I didn't think it was complicated enough. OK,
thought for today:
(snip)

Does the following generate a gated clock?

The following statement must be done before the rest. While simulators may
execute them in order, synthesized logic tends to execute them all at the
same time.

Does this generate a gated clock? Can you do it in traditional synchronous
logic form, where either the previous contents, or the contents with "0011"
added are loaded back in? (Also with the shift_en_s enable.)

(snip)
Gated clocks are especially hard in FPGA's.
-- glen

Re: binary to BCD assistance

Not if it follows the line
elsif rising_edge(clk) then
in a synchronous process.
It's the process template that
gives you a synchronous clock, not
any single sequential statement.

Actually, the synth will give you a netlist that simulates
the same as that code, executed in order.
Sequential statements execute in zero sim time.
The only delay is for rising_edge(clk).
Your code is a hardware specification that can only
be completely understood in the context of simulation. There is
usually no one-to-one correspondence between code statements
and the synthesis netlist components.

This synthesizes nothing unless bcd_value is assigned
directly or indirectly to an entity port.
If this assignment occurs within a synchronous process,
the output will be registered by clk.

If you stick to the synchronous process template, you
will never have one to worry about.
-- Mike Treseler

Re: binary to BCD assistance
Hi Jason,
I found your algorithm in C (see source after the vhdl code) on the net.
It's cool.
I rewrited your code like this (see bellow) and it works fine (I tested):
(bin and bcd width (20 and 24) could be replaced by constants (C_BIN_WIDTH,
C_BCD_WIDTH)).
Hope this will help.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd is
port(
i_clk : in std_logic;
i_rst_an : in std_logic;
i_load_data : in std_logic;
i_data : in std_logic_vector(20-1 downto 0);
o_data_rdy_q : out std_logic;
o_data_q : out std_logic_vector(24-1 downto 0)
);
end bin2bcd;
architecture rtl of bin2bcd is
begin
--------------------------------------------------------------------------
----
-- register mapping:
--
-- ------------------------
-- | v_bcd_bin_q |
-- ------------------------
-- | av_bcd_q | |
-- ------------------------
-- | | av_bin_q |
-- ------------------------
-- |xxx| 3 bits overlaps to save 3 clk cycle processing and 3
dff
--
--------------------------------------------------------------------------
----
ps_bin2bcd : process (i_rst_an, i_clk)
variable v_cnt_q : integer range 0 to 17;
variable v_en_shift_q : std_logic;
variable v_data_rdy_q : std_logic;
variable v_bcd_bin_q : unsigned(20+24-3-1 downto 0);
alias av_bin_q : unsigned(20-1 downto 0) is v_bcd_bin_q(20-1 downto 0);
alias av_bcd_q : unsigned(24-1 downto 0) is v_bcd_bin_q(20+24-3-1 downto
20-3);
begin
if i_rst_an = '0' then
v_cnt_q := 0;
v_en_shift_q := '0';
v_bcd_bin_q := (others => '0');
v_data_rdy_q := '0';
elsif rising_edge(i_clk) then
if i_load_data = '1' then
av_bcd_q := (others => '0');
av_bin_q := unsigned(i_data);
v_cnt_q := 0;
v_en_shift_q := '1';
v_data_rdy_q := '0';
elsif v_cnt_q = 17 then
v_bcd_bin_q := v_bcd_bin_q; -- optional assignment
v_cnt_q := v_cnt_q; -- optional assignment
v_en_shift_q := '0';
v_data_rdy_q := '1';
elsif v_en_shift_q = '1' then
for i in 0 to 5 loop
if av_bcd_q(4*i+3 downto 4*i) >= 5 then
av_bcd_q(4*i+3 downto 4*i) := av_bcd_q(4*i+3 downto 4*i) + 3;
end if;
end loop;
v_bcd_bin_q := v_bcd_bin_q sll 1;
v_cnt_q := v_cnt_q + 1;
v_en_shift_q := v_en_shift_q; -- optional assignment
v_data_rdy_q := v_data_rdy_q; -- optional assignment
else
v_bcd_bin_q := v_bcd_bin_q; -- optional assignment
v_cnt_q := v_cnt_q; -- optional assignment
v_en_shift_q := v_en_shift_q; -- optional assignment
v_data_rdy_q := v_data_rdy_q; -- optional assignment
end if;
end if;
o_data_q <= std_logic_vector(av_bcd_q);
o_data_rdy_q <= v_data_rdy_q;
end process;
end rtl;
**********C source code************
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define BIN_SIZE 4
#define MSB_MASK 0x80000000L
#define BCD_SIZE 13
typedef unsigned long BIN;
typedef unsigned char BCD[BCD_SIZE];
main()
{
BIN bin1,bin;
BCD bcd;
int i,j,k,carry;
char temp[9];
printf("enter number:");
scanf("%lu", &bin1);
bin=bin1;
for (i=0; i<= BCD_SIZE; i++) bcd[i]=0;
printf("\n BCD BIN\n");
for (i=0; i<8*BIN_SIZE; i++) {
/* check for overflow */
for (j=0; j<BCD_SIZE; j++) {
if (bcd[j] >= 5) {
bcd[j] += 3;
/* printout for checking */
for (kBC%D_SIZE; k--; ) printf("%4s ", itoa(bcd[k],temp,2));
printf(" %x\n", bin);
}
}
/* shift right */
carry = (bin & MSB_MASK) == MSB_MASK;
bin = bin << 1;
for (j=0; j<BCD_SIZE; j++) {
bcd[j] = (bcd[j] << 1) | carry;
carry = (bcd[j] & 0x10) == 0x10;
bcd[j] = bcd[j] & 0xF;
}
/* printout for checking */
for (kBC%D_SIZE; k--; ) printf("%4s ", itoa(bcd[k],temp,2));
printf(" %x\n", bin);
}
printf("BIN = %lu\n", bin1);
printf("BCD = ");
for (kBC%D_SIZE; k--; ) printf("%d", bcd[k]);
}
regards
FE

sure
The
Start
greater
representation.
counter,
attempting
and
load
to
from
I found your algorithm in C (see source after the vhdl code) on the net.
It's cool.
I rewrited your code like this (see bellow) and it works fine (I tested):
(bin and bcd width (20 and 24) could be replaced by constants (C_BIN_WIDTH,
C_BCD_WIDTH)).
Hope this will help.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd is
port(
i_clk : in std_logic;
i_rst_an : in std_logic;
i_load_data : in std_logic;
i_data : in std_logic_vector(20-1 downto 0);
o_data_rdy_q : out std_logic;
o_data_q : out std_logic_vector(24-1 downto 0)
);
end bin2bcd;
architecture rtl of bin2bcd is
begin
--------------------------------------------------------------------------
----
-- register mapping:
--
-- ------------------------
-- | v_bcd_bin_q |
-- ------------------------
-- | av_bcd_q | |
-- ------------------------
-- | | av_bin_q |
-- ------------------------
-- |xxx| 3 bits overlaps to save 3 clk cycle processing and 3
dff
--
--------------------------------------------------------------------------
----
ps_bin2bcd : process (i_rst_an, i_clk)
variable v_cnt_q : integer range 0 to 17;
variable v_en_shift_q : std_logic;
variable v_data_rdy_q : std_logic;
variable v_bcd_bin_q : unsigned(20+24-3-1 downto 0);
alias av_bin_q : unsigned(20-1 downto 0) is v_bcd_bin_q(20-1 downto 0);
alias av_bcd_q : unsigned(24-1 downto 0) is v_bcd_bin_q(20+24-3-1 downto
20-3);
begin
if i_rst_an = '0' then
v_cnt_q := 0;
v_en_shift_q := '0';
v_bcd_bin_q := (others => '0');
v_data_rdy_q := '0';
elsif rising_edge(i_clk) then
if i_load_data = '1' then
av_bcd_q := (others => '0');
av_bin_q := unsigned(i_data);
v_cnt_q := 0;
v_en_shift_q := '1';
v_data_rdy_q := '0';
elsif v_cnt_q = 17 then
v_bcd_bin_q := v_bcd_bin_q; -- optional assignment
v_cnt_q := v_cnt_q; -- optional assignment
v_en_shift_q := '0';
v_data_rdy_q := '1';
elsif v_en_shift_q = '1' then
for i in 0 to 5 loop
if av_bcd_q(4*i+3 downto 4*i) >= 5 then
av_bcd_q(4*i+3 downto 4*i) := av_bcd_q(4*i+3 downto 4*i) + 3;
end if;
end loop;
v_bcd_bin_q := v_bcd_bin_q sll 1;
v_cnt_q := v_cnt_q + 1;
v_en_shift_q := v_en_shift_q; -- optional assignment
v_data_rdy_q := v_data_rdy_q; -- optional assignment
else
v_bcd_bin_q := v_bcd_bin_q; -- optional assignment
v_cnt_q := v_cnt_q; -- optional assignment
v_en_shift_q := v_en_shift_q; -- optional assignment
v_data_rdy_q := v_data_rdy_q; -- optional assignment
end if;
end if;
o_data_q <= std_logic_vector(av_bcd_q);
o_data_rdy_q <= v_data_rdy_q;
end process;
end rtl;
**********C source code************
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define BIN_SIZE 4
#define MSB_MASK 0x80000000L
#define BCD_SIZE 13
typedef unsigned long BIN;
typedef unsigned char BCD[BCD_SIZE];
main()
{
BIN bin1,bin;
BCD bcd;
int i,j,k,carry;
char temp[9];
printf("enter number:");
scanf("%lu", &bin1);
bin=bin1;
for (i=0; i<= BCD_SIZE; i++) bcd[i]=0;
printf("\n BCD BIN\n");
for (i=0; i<8*BIN_SIZE; i++) {
/* check for overflow */
for (j=0; j<BCD_SIZE; j++) {
if (bcd[j] >= 5) {
bcd[j] += 3;
/* printout for checking */
for (kBC%D_SIZE; k--; ) printf("%4s ", itoa(bcd[k],temp,2));
printf(" %x\n", bin);
}
}
/* shift right */
carry = (bin & MSB_MASK) == MSB_MASK;
bin = bin << 1;
for (j=0; j<BCD_SIZE; j++) {
bcd[j] = (bcd[j] << 1) | carry;
carry = (bcd[j] & 0x10) == 0x10;
bcd[j] = bcd[j] & 0xF;
}
/* printout for checking */
for (kBC%D_SIZE; k--; ) printf("%4s ", itoa(bcd[k],temp,2));
printf(" %x\n", bin);
}
printf("BIN = %lu\n", bin1);
printf("BCD = ");
for (kBC%D_SIZE; k--; ) printf("%d", bcd[k]);
}
regards
FE

sure
The
Start
greater
representation.
counter,
attempting
and
load
to
from

Re: binary to BCD assistance
Hi Jason,
First off, that's a pretty cool little algorithm... had to prove to myself
that it worked. Let digit = 5 + n, where n = 0..4. We want new_digit =
(digit * 2 + shift_in) % 10 = (5 * 2 + n * 2 + shift_in) % 10 = n * 2 +
shift_in. If we add three, and wrap around at 16 (since 4-bit
representation) then we get ((8 + n) * 2 + shift_in) % 16 = 2 * n +
shift_in.
I'm not sure that I've found the problem with your code, but there were a
number of stylistic issues and one suspicious fragment I figured I'd point
out. I'll add a caveat that I haven't really coded up any VHDL in a year or
so, and prior to that my experience was mostly with structural VHDL. And I
didn't have a compiler handy to try out my ideas. So I imagine I'll find
out I'm wrong and learn something in the process!
(0) I think the first problem is a lack of comments... uncommented code is
always wrong :-)
(1) Process #3. I hate variables. Especially variables mixed with
signals... you must be very disciplined when using variables (I only use
them in for loops...). So I honestly don't know what the code will
translate into, as you are assigning a value to variable, then assigning to
the variable to a signal, then changing the value of the variable. I'm not
sure if the scheduled signal assignment occurs before or after the change in
variable value. Also, I'm not sure that the variable turns into a register
(i.e. has memory) -- either way though, it's not what you want. If it does
become a register, then have 2 24-bit registers (unnecsessary/may not work).
If you don't, then I don't know what will happen. Regardless, I think you
want to first be adding three, THEN shifting. There are two ways I can
think of restructuring this code into something that may work (see below).
The first replaces your variable with a signal that is computed
combinationally outside of the process. The second is an attempt to still
use a variable, based on my limited understanding of this VHDL construct.
Note that neither requires the asynchronous condition (though I'm thinking
it may need an aclr for bcd_out_s...).
if clk = '1' and clk'event then
if load_data = '1' then
bcd_out_s <= (OTHERS => '0');
elsif shift_en_s = '1' then
bcd_out_s <= bcd_out_modified_s(22 downto 0) & ser_out_s;
end if;
end if;
...
bcd_out_modified_s(3 downto 0) <= bcd_out_s(3 downto 0) + "0011" when
bcd_value(3 downto 0) >= "0101" else bcd_value(3 downto 0);
...
or:
if clk = '1' and clk'event then
if load_data = '1' then
bcd_out_s <= (OTHERS => '0');
elsif shift_en_s = '1' then
bcd_value := bcd_out_s;
if bcd_value(3 downto 0) >= "0101" then
bcd_value(3 downto 0) := bcd_value(3 downto 0) + "0011";
end if;
...
bcd_out_s <= bcd_value(22 downto 0) & ser_out_s;
end if;
end if;
I'm sure there are other ways to structure the code, and my way may add an
additional clock cycle or may need an extra bit in the register to work
right, but you get the idea.
(2) Process #3 makes use of an asynchronous clear on the condition of
load_data. If you can do something synchronously instead of asynchronously,
you should. There's no harm in putting another if clause in your clocked
portion of the process to cover the clear while loading case.
(3) Process #2. You have two if statements, both of which affect bin_in_s:
if load_data = '1' then
bin_in_s <= data_in;
end if;
if shift_en_s = '1' then
bin_in_s <= bin_in_s(18 downto 0) & '0';
end if;
While legal, the interpretation (I think) is the same as the following code,
which is cleaner and thus less likely to be incorrect. My experience is
whenever I try to be as smart as the compiler, I end up getting bitten by it
later...
if shift_en_s = '1' then
bin_in_s <= bin_in_s(18 downto 0) & '0';
elsif load_data = '1' then
bin_in_s <= data_in;
end if;
(4) Process #1 & #4. You are instantiating many more registers than
necessary. You could get away without the data_out register (unless you
want to be able to process new data while some other chip takes its time
reading your result, which seems unlikely). Also, you are inserting an
extra cycle of latency with your data_ready & data_out registers. But there
should be nothing functionally wrong there.
(5) Your asynchronous reset may not be safe. The topic of many discussions.
Not the problem you're having now I bet.
Good luck,
Paul Leventis
First off, that's a pretty cool little algorithm... had to prove to myself
that it worked. Let digit = 5 + n, where n = 0..4. We want new_digit =
(digit * 2 + shift_in) % 10 = (5 * 2 + n * 2 + shift_in) % 10 = n * 2 +
shift_in. If we add three, and wrap around at 16 (since 4-bit
representation) then we get ((8 + n) * 2 + shift_in) % 16 = 2 * n +
shift_in.
I'm not sure that I've found the problem with your code, but there were a
number of stylistic issues and one suspicious fragment I figured I'd point
out. I'll add a caveat that I haven't really coded up any VHDL in a year or
so, and prior to that my experience was mostly with structural VHDL. And I
didn't have a compiler handy to try out my ideas. So I imagine I'll find
out I'm wrong and learn something in the process!
(0) I think the first problem is a lack of comments... uncommented code is
always wrong :-)
(1) Process #3. I hate variables. Especially variables mixed with
signals... you must be very disciplined when using variables (I only use
them in for loops...). So I honestly don't know what the code will
translate into, as you are assigning a value to variable, then assigning to
the variable to a signal, then changing the value of the variable. I'm not
sure if the scheduled signal assignment occurs before or after the change in
variable value. Also, I'm not sure that the variable turns into a register
(i.e. has memory) -- either way though, it's not what you want. If it does
become a register, then have 2 24-bit registers (unnecsessary/may not work).
If you don't, then I don't know what will happen. Regardless, I think you
want to first be adding three, THEN shifting. There are two ways I can
think of restructuring this code into something that may work (see below).
The first replaces your variable with a signal that is computed
combinationally outside of the process. The second is an attempt to still
use a variable, based on my limited understanding of this VHDL construct.
Note that neither requires the asynchronous condition (though I'm thinking
it may need an aclr for bcd_out_s...).
if clk = '1' and clk'event then
if load_data = '1' then
bcd_out_s <= (OTHERS => '0');
elsif shift_en_s = '1' then
bcd_out_s <= bcd_out_modified_s(22 downto 0) & ser_out_s;
end if;
end if;
...
bcd_out_modified_s(3 downto 0) <= bcd_out_s(3 downto 0) + "0011" when
bcd_value(3 downto 0) >= "0101" else bcd_value(3 downto 0);
...
or:
if clk = '1' and clk'event then
if load_data = '1' then
bcd_out_s <= (OTHERS => '0');
elsif shift_en_s = '1' then
bcd_value := bcd_out_s;
if bcd_value(3 downto 0) >= "0101" then
bcd_value(3 downto 0) := bcd_value(3 downto 0) + "0011";
end if;
...
bcd_out_s <= bcd_value(22 downto 0) & ser_out_s;
end if;
end if;
I'm sure there are other ways to structure the code, and my way may add an
additional clock cycle or may need an extra bit in the register to work
right, but you get the idea.
(2) Process #3 makes use of an asynchronous clear on the condition of
load_data. If you can do something synchronously instead of asynchronously,
you should. There's no harm in putting another if clause in your clocked
portion of the process to cover the clear while loading case.
(3) Process #2. You have two if statements, both of which affect bin_in_s:
if load_data = '1' then
bin_in_s <= data_in;
end if;
if shift_en_s = '1' then
bin_in_s <= bin_in_s(18 downto 0) & '0';
end if;
While legal, the interpretation (I think) is the same as the following code,
which is cleaner and thus less likely to be incorrect. My experience is
whenever I try to be as smart as the compiler, I end up getting bitten by it
later...
if shift_en_s = '1' then
bin_in_s <= bin_in_s(18 downto 0) & '0';
elsif load_data = '1' then
bin_in_s <= data_in;
end if;
(4) Process #1 & #4. You are instantiating many more registers than
necessary. You could get away without the data_out register (unless you
want to be able to process new data while some other chip takes its time
reading your result, which seems unlikely). Also, you are inserting an
extra cycle of latency with your data_ready & data_out registers. But there
should be nothing functionally wrong there.
(5) Your asynchronous reset may not be safe. The topic of many discussions.
Not the problem you're having now I bet.
Good luck,
Paul Leventis

Re: binary to BCD assistance

The best and quickest way to do both is to write a testbench an run a sim.
This quickly resolves all questions about how the langage works
and how the logic functions.

My favorite comments are a plain text description at the top of each
process about function and handshake protocols.
These can be collected at the top of the architecture after the
sim is working.
Detail comments at the end of line, can often be replaced by
by well-named statement labels, constants and variables.

Signals are the only way in and out of a process.

In the case referenced, the first value is exported to the signal at
the next clk and the second value is held by the variable until the next clk, if
it is needed.
This is not as complex as you think. Variables are stuck inside the process.
They only reach the entity ports if you make a signal assignment inside
the process. Synthesis will use a register to save the variable's *final* value.
only if this value is needed at the next clk.
Run a sim sometime, and watch the variables as you trace code.
-- Mike Treseler

Re: binary to BCD assistance
Here is a time-proven hardware design for bit-serial binary to parallel
BCD conversion. (I published this in 1973 in the Fairchild TTL
Applications Handbook).
Implement a bunch of 4-bit loadable shift register, but do not
interconnect them.
For each shift register drive a 4-bit adder (without carry in, but with
carry output) from the 4 shift register outputs. Put a binary eleven (B)
as other input on the adder.
Connect the adder outputs to the shift register load inputs, but skewed
one position downstream ( bit 0 of the adder drives bit 1 of the shift
register ).
Then use the carry output as load enable for "its" shift register, and
also as input for the LSB of the downstream shift register ( both as
shift- and as load- input)
The S3 output ( most significant sum) goes nowhere. That's it.
Shifting in binary data (MSB first) doubles the binary value on every
shift. The adder monitors this and, on its carry output, signals that
there is a value 5 or larger, which needs intervention: add 3 before the
next shift ( which is equivalent to adding 6 after having shifted it)
and load a carry into the next higher bit position.
The neat trick is that the 4-bit adder simultaneously adds eleven to
create a carry that detects the need for modification, and also adds
three to do the modification.
Shift in binary data, MSB first, and watch the BCD develop on the
parallel shift register outputs. Note that BCD needs more bit positions
than binary, so leave some headroom.
Works like a champ, flawlessly since 30 years ago.
Peter Alfke, no longer at Fairchild (but it was an interesting 10 years)
====================
Mike Treseler wrote:

if

value.

BCD conversion. (I published this in 1973 in the Fairchild TTL
Applications Handbook).
Implement a bunch of 4-bit loadable shift register, but do not
interconnect them.
For each shift register drive a 4-bit adder (without carry in, but with
carry output) from the 4 shift register outputs. Put a binary eleven (B)
as other input on the adder.
Connect the adder outputs to the shift register load inputs, but skewed
one position downstream ( bit 0 of the adder drives bit 1 of the shift
register ).
Then use the carry output as load enable for "its" shift register, and
also as input for the LSB of the downstream shift register ( both as
shift- and as load- input)
The S3 output ( most significant sum) goes nowhere. That's it.
Shifting in binary data (MSB first) doubles the binary value on every
shift. The adder monitors this and, on its carry output, signals that
there is a value 5 or larger, which needs intervention: add 3 before the
next shift ( which is equivalent to adding 6 after having shifted it)
and load a carry into the next higher bit position.
The neat trick is that the 4-bit adder simultaneously adds eleven to
create a carry that detects the need for modification, and also adds
three to do the modification.
Shift in binary data, MSB first, and watch the BCD develop on the
parallel shift register outputs. Note that BCD needs more bit positions
than binary, so leave some headroom.
Works like a champ, flawlessly since 30 years ago.
Peter Alfke, no longer at Fairchild (but it was an interesting 10 years)
====================
Mike Treseler wrote:

if

value.

Site Timeline
- » Synthesisable fixed-point arithmetic package
- — Next thread in » Field-Programmable Gate Arrays
-
- » Re: Multi Cycle path and False paths
- — Previous thread in » Field-Programmable Gate Arrays
-
- » Achronix Semiconductor in Talks for Merger
- — Newest thread in » Field-Programmable Gate Arrays
-
- » Samstag ist Antennentag - 2 parallele Dipole mit Phasenverschiebung der Speisung
- — The site's Newest Thread. Posted in » Electronics (German)
-