Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Simple Binary to BCD conversions

Status
Not open for further replies.

Mynci

Technical User
Oct 31, 2002
16
GB
hi, i know this is simple stuff, but it has been driving me mad trying to implement it. i have a number stored as a 32bit std_logic_vector. i need to convert it into bcd for display.
im sure this is fantastically simple and annoying to be asked how to do it, but im yet to find a simple (and non rescource hungry) method.

if anyone could point me at any guides to how this should be done i would very, very much appreciate it, i have read through just about all the information i can dig up on google and they all seem to implement the conversion in parallel (for a 32 bit numbers this seems unweildy) or in other ways that i simply cant get my head around.

i have made an attempt to implement the circuit discussed here:


As i can see if i chained them together it would provide me with a possible solution, unfortunatley my attempts at creating the circuit have been entirely unsuccessful (i can post the code, if it would be helpful).

any guidance on this would be very much apreciated.

cheers
mynci
 
This all depends on what you actually need to do with the result.

For example. if you only need to display the number then you can simply do the conversion for each character and display each character side-by-side to give you a number:

but if you need to manipulate the binary number using math then I guess you need to create the real number:

ie 623 could be six hundred twenty three, or it could simply be six two three concatinated together.

Since you are having problems my guess is that you really do require the six hundred twenty three. right of the top of my head I am struggling for a non-resource hungry version of this code myself.

how are you displaying this number? do you really need a real integer or can 8 digits concatinated work too?

--
 
oh, I missed something there... I thought you had bcd format and need to display it. but you need to convert to bcd.... so that explains my confusion.

let me think.

--
 
thank you very much VHDLguy. im sorry if it wasnt clear, i have a 32 bit binary number and need to display each of the digits ona seven segment display.
however due to the way this problem is preseted the outputs are of a more abtract type than simply BCD, ie the unit must out put a value of 'one' for 1, but this part is academic, ie if i can determine each digits value then what is used to represent it is unimportant.

as i mentioned in the above link there is a nice solution but i have been unable to convert the circuit into working code.

many thanks once again.
mynci
 
I don't think you are going to get any easier than the circuit you posted.

Show me your code where you tried to implement this and I will try and help you out.


Your best bet would be to create an entity that just does the 4 bit manipulation as shown, then string a bunch of them together. You will end up needing about 10 of them i guess.

Anyway, post your code and we can go from there.

--
 
seven segment display? meaning you can only display 7 characters? or are you going to have a rolling display?

either that or you know that your number will never be more than 10 million (regardless of it being in a 32 bit number).

anyway, thats a side issue.

--
 
it will be displayed on a set of ten 7 segment displays (the led digit read-out things - is that not a standard term?), the integer is 2's comp(but i can deal the negative seperately, i hope :) )

the code i have (and this has been altered from the original somewhat in my attempts to make it work, but i think the general idea is there.
i have basically tried to deconstrcut the circuit, however i think will have made several errors (as the circuit rendered is no where near what i was after-and does not simulate at all well)

heres the code:
------------------------------------------

entity SerBCDBin is
Port ( MODin : in std_logic;
clk : in std_logic;
en : in std_logic;
rst : in std_logic;
MODout : out std_logic;
Q0 : out std_logic;
Q1 : out std_logic;
Q2 : out std_logic;
Q3 : out std_logic
);
end SerBCDBin;

architecture Behavioral of SerBCDBin is
begin

process (clk)
variable Q0_old, Q1_old, Q2_old, Q3_old, Q0_new, Q1_new, Q2_new, Q3_new : std_logic;
variable modtest : std_logic_vector(3 downto 0);
variable MODOut_Int : std_logic;
begin

if (clk'event) and clk = '1' then
if en = '1' then

if rst = '1' then
Q0_old:='0';
Q1_old:='0';
Q2_old:='0';
Q3_old:='0';
Q0_new:='0';
Q1_new:='0';
Q2_new:='0';
Q3_new:='0';
else
modtest := Q0_old & Q1_old & Q2_old & Q3_old;

if modtest >= "101" then
MODOut_Int := '1';
MODout <= '1';
else
MODOut_Int := '0';
MODout <= '0';
end if; --modtest for 5 or greater

if MODOut_Int = '1' then
Q3_new := Q1_old and Q3_old;
Q2_new := Q0_old xnor Q1_old;
Q1_new := not Q1_old;
Q0_new := MODIn;
else
Q3_new := Q2_old;
Q2_new := Q1_old;
Q1_new := Q1_old;
end if; --mod out_int


--set outputs to current value
Q0_old := Q0_new;
Q1_old := Q1_new;
Q2_old := Q2_new;
Q3_old := Q3_new;


Q0 <= Q0_old;
Q1 <= Q1_old;
Q2 <= Q2_old;
Q3 <= Q3_old;

--make the new value the old value;


end if;--en

end if; --rst
end if; --clk


end process;


end Behavioral;

------------------------------------------

i intended to create a device that would only change its output when enabled, and then the reset, or actual function could occur.

i initially coded this with two processes, one sensitive to the inputs (trying to simulate the logic of the circuit) and one sensitive to the clock (trying to simulate the memory part, tis didnt work as intended though)

if this code doesnt make sense then please let me know and ill do my best to comment my intentions.

im sure this isnt particularly well coded, but im having a bit of trouble with the conceptual leap between software programming and this type of HDL.

cheers
mynci.
 
Firstly the obvious coding error that jumps out is modtest.

if you define a variable or signal as a vector then the order is the same as the definition.

so modtest as a (3 downto 0) should be concatinated as:
modtest := Q3_old & Q2_old & Q1_old & Q0_old;

now looking at the actual logic:

The second thing that I see is that you don't assign q0 to modin when modout_int is not 1.

thirdly q1 should be equal to q0_old when modout_int is not 1 and "not q0_old" when modout_int is 1.

finally when modout_int is 1 q3 should be q0_old and q3_old.

personally I don't like variables, I find its too easy to make mistakes, and I only use them when absolutely required. I prefer signals simply because my mind works better with real logic gates etc and signals more closely represent that.

That is my disclaimer because the rest of your code looks ok, but I am not used to thinking about variables, so I may have missed something. :)

So once you have done that you will need to string 10 instances of SerBCDBin together. have you done that correctly?





--
 
thanks a lot, i shall make those modifications. i think i have got the joins ok, i (think) i can handle stuctural creations ok (they make more sense to me), but i shall let you know how i get on.

the modtest thing is obvious, im embarrased for not spotting it :)

i wasnt sure how to implement the flip flop 'storage' without using variables (and i have been told not to over use structural definitions, or else i would have bitten the bullet and just made the circuit from gates.

ill let you know how it goes, thanks a lot.
 
ok, heres the modified code, i havent had chance to test it (will do ina few hours), but i thought it may have been of interest, or you may spot another glaring ommision.

cheers

mynci


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following lines to use the declarations that are
-- provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;

entity SerBCDBin is
Port ( MODin : in std_logic;
clk : in std_logic;
en : in std_logic;
rst : in std_logic;
MODout : out std_logic;
Q0 : out std_logic;
Q1 : out std_logic;
Q2 : out std_logic;
Q3 : out std_logic
);
end SerBCDBin;

architecture Behavioral of SerBCDBin is
begin

process (clk)
variable Q0_old, Q1_old, Q2_old, Q3_old, Q0_new, Q1_new, Q2_new, Q3_new : std_logic;
variable modtest : std_logic_vector(3 downto 0);
variable MODOut_Int : std_logic;
begin

if (clk'event) and clk = '1' then
if en = '1' then

if rst = '1' then
Q0_old:='0';
Q1_old:='0';
Q2_old:='0';
Q3_old:='0';
Q0_new:='0';
Q1_new:='0';
Q2_new:='0';
Q3_new:='0';
else
modtest := Q3_old & Q2_old & Q1_old & Q0_old;

if modtest >= "101" then
MODOut_Int := '1';
MODout <= '1';
else
MODOut_Int := '0';
MODout <= '0';
end if; --modtest for 5 or greater

if MODOut_Int = '1' then
Q3_new := Q3_old and Q1_old;
Q2_new := Q0_old xnor Q1_old;
Q1_new := not Q0_old;
Q0_new := MODIn;
else
Q3_new := Q2_old;
Q2_new := Q1_old;
Q1_new := Q0_old;
Q0_new := MODIn;
end if; --mod out_int


--set outputs to current value
Q0_old := Q0_new;
Q1_old := Q1_new;
Q2_old := Q2_new;
Q3_old := Q3_new;

MODOut <= MODOut_Int;
Q0 <= Q0_old;
Q1 <= Q1_old;
Q2 <= Q2_old;
Q3 <= Q3_old;

--make the new value the old value;


end if;--en

end if; --rst
end if; --clk


end process;


end Behavioral;
 
i think i am getting somewhere with this, however i dont think that the logic is quite correct in the conversion unit.

at the bottom is a link to the whole project file(i thought this was easier, as you could see all the data types and method of simulation etc). if you could be bothered to take a look at it, as i cannoot see where the problem is (although i suspect the logic in the unit), i would very much apreciate it, however i suspect i am pushing your very kind help to the limit, so i understand entirely if you dont have time or just cant be bothered.

the most curious problem that makes me sure that there is an issue is that the circuit (the cascade) keeps generating 'numbers' on the output even when there is no input value for a long period of time.

the files in the package are:
SerBCDBin (the individual unit as shown in the circuit, contains the code discussed above)
--testbcd (a testbed for the single entity)

converter (a architectural definition stringing ten of the converters together)
--converter test (test bed for the chain)

calpack contains the 'key_type' definitions.


very many thanks
mynci

 
you missed my last logic error:
when modout_int is 1, q3 should be "q0_old and q3_old".

And looking at your zip file it seems you made the same concatination mistake with the signal digit_int. But you probably just didn't get to that yet.

I can't compile your design since I don't have your calculator package, but I think that what I mentioned above should help.

As for the variable/signal question. You did a good job with the variables. With signals you just have to remember that any changes don't occur until the next clock. So you have to learn to ignore what has already happened in that process (unless it was a variable) and remember that the signal will still have the same value as it got at the last clock cycle.

I would write the above (with fix I mentioned) as something like this:

process (clk)

begin

if (clk'event) and clk = '1' then
if en = '1' then

if rst = '1' then
Q <= "0000";
else

if Q >= "0101" then
MODout <= '1';
Q(3) <= Q(3) and Q(0);
Q(2) <= Q(0) xnor Q(1);
Q(1) <= not Q(0);
Q(0) <= MODin;
else
MODout <= '0';
Q(3 downto 1) <= Q(2 downto 0);
Q(0) <= MODin;
end if; --modtest for 5 or greater


end if;--en

end if; --rst
end if; --clk


end process;


--
 
thank you once again.

i think i will keep making the same error on concatenations from now on, like some sort of curse.

i have managed to make the unit work wnen free standing (ie just one, with a four bit number).
i am not sure if its correct but i have attempted to enable the next unit after six clock cycles (the amount of time it takes for the first unit to display a valid number), it does nto work correctly when cascaded though. i have created a new zip (link below) with, i believe, all of the files needed to compile this in it.

if you have got time to check it i woudl very much apreciate it.

---------------------------------

the files are:
converter - a chain of ten conversion units, the number to be converted is shifted into unit 9 msb first. as it stands when the first unit has recieved 6 clock pulses it will switch onthe next one. i think this is not correct though.

convertertest - a test bench for the chain of converters.

SerBCDBin - the definition of a single device, this now seems too work, using a mix of the code you wrote and the original. it outputs the type 'key_type'

TestSerBCDBin - a test bench for a single converter, when EnNext goes high the answer on the output is valid

calpack - this just has the key type definition

-------------------------------------------

luckily (sort of) i have plenty of other parts to create, and so can keep coming back to this 'fresh' so i may spot the problems, however if there is something glaring, im sure you will spot it far, far quicker than me.

again i apreciate i am asking a lot, and wont be in the elast bit offended if you simply hhavent got time to sift through my code.

many thanks
mynci

The link:
 
a few more things to add (sorry):

i noticed i was shifting the data in to the test array MSB first, it should (I think) be LSb first. i have removed the delay that stopped each one being enabled for 6 clock cycles as i think it was wrong (i have just tied each of the enables to 1, for the sake of testing)

i am stil not getting the correct answer. i have also notciced that the unit is being sythesised using a bram (i think) block, and therefore using up 100% of the chips rescources. is it possible to force it not to do this?

i will give your code another try, and see if that helps. but when i tried before it didnt seem t work (however that could be an MSB/LSB issue)

cheers
mynci
 
sorry, one last update, i have overwritten the old file linked above with the new code (which uses your logic code directly - i decided that it would be better as it rendered to a cct much more elegantly). i am at a loss to getting it to work as exppected though.

i have tried shifting the numebrs in msb and lsb first and at no point can i get the type of numbers i would expect. the test file for the converter array uses the decimal 12901 to test it however the output represent this.

looking at the original document it impliews that the numebr shoudl be shifted into the unit that will display the most significant digit first, LSB first. so for anny 32 bit number each of the 32 bits (including the leading zero's) would need to be shifted in before an answer would apppear. this would meen that as the leading zeroes of a number are shifted in to the higher digit blocks (and the lsb's reach the lower ones) the higher digit blocks would start to show zero again, this does not happen regardless of how long zeros are shifted into the Bit input.

does this imply that the logic is wrong? or am i attempting to implemment the (possibly) working Blocks into a larger array incorrectly?

this is starting to get more annoying than challenging, but im sure if i persevere i will find a solution. as always any guidance from anyone iis very very much apreciated.

cheers
mynci

(heres the link again:
 
just realised, the ram blocks that it implements are for my 'case' structure to determine the key type, i will get round this once i have the blocks working, by muxing the 4 bit bcd outputs into one 'key_type' converter.

now just to work out why it isnt doign what i want it to :)

cheers
mynci
 
right, i may have made another advance. because of this line fromt he original document:

"To start a new conversion, INIT should be asserted at the time the binary MSB is applied to the converter input. INIT clears all bits except the LSB which is loaded."

this sort of implies that instead of being a 'not enable' it is required to load Q(0) when init goes low, and that this shoudl be done when the msb is placed on the input to the converter. i have tried this, and i get a similar result. the converter seems to work for some 2 digit numbers but has the wrong output at the same time on each unit, ie the correct answer can be got by taking a reading form each unit at certain time increments. however this is not always the case and implies a coincidence rather than a part working encoder.

i am now shifting numebers in MSB first, into the least significant decimal digit first. i am fairly confident that this is correct.

the other modification, with reference to the init, is the following code:

if (init'event) and init = '0' then
Q <= "000" & MODIn;
MODOut <= '0';
end if;

this happens when the first digit is placed on the input of the converter array, this is nominally a zero (for smaller numbers).

shoould each unit have init asserted when the first non zero bit is placed in the MODIn?
is there still a glaring error in my code?

im sure my many updates has confused the issue somewhat so if you need anyything to help you work out where i am, please ask.


i have now completed almost all other parts of this so i just need to get this right and im pretty much sorted. so any help would be very very much apreciated.

cheers
mynci.
 
asserting the init to zero when the first '1' is placed on the mod in, makes no difference.

this may be obviouss, but i thought it better to try it.

cheers

mynci.
 
I have finally got somewhere, this code seems to work (this is one unit):

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.calculator_package.ALL;
-- Uncomment the following lines to use the declarations that are
-- provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;

entity SerBCDBin is
Port ( MODin : in std_logic;
clk : in std_logic;
init : in std_logic;
rst : in std_logic;
MODout : out std_logic;
DigitOut : out key_type
);
end SerBCDBin;

architecture Behavioral of SerBCDBin is
signal Q : std_logic_vector(3 downto 0);
signal MODOut_int : std_logic;

begin

process (clk)
begin

if (clk'event) and clk = '1' then

--resets regardless of enable state
if rst = '1' or init = '1' then
Q <= "0000";
else
if MODout_int = '1' then
Q(3) <= Q(0) and Q(3);
else
Q(3) <= Q(2);
end if;
Q(3) <= Q(3) and Q(0);
if MODout_int = '1' then
Q(2) <= Q(0) xnor Q(1);
else
Q(2) <= Q(1);
end if;
Q(1) <= Q(0) xor MODOut_int;
Q(0) <= MODin;

end if; --rst

end if;--clk
end process;
----------------------------------------------------------------------------------------------------------------
process (Q, init)
begin
if init = '1' then
MODout_int <= '0';
elsif Q >= "0101" then
MODout_int <= '1';
else
MODout_int <= '0';
end if;
end process;
----------------------------------------------------------------------------------------------------------------
MODout <= MODOut_int;

----------------------------------------------------------------------------------------------------------------
process (Q)
begin
case Q is
when "0000" => DigitOut <= zero;
when "0001" => DigitOut <= one;
when "0010" => DigitOut <= two;
when "0011" => DigitOut <= three;
when "0100" => DigitOut <= four;
when "0101" => DigitOut <= five;
when "0110" => DigitOut <= six;
when "0111" => DigitOut <= seven;
when "1000" => DigitOut <= eight;
when "1001" => DigitOut <= nine;
when others => DigitOut <= no_key;
end case;
end process;

end Behavioral;

-------------------

where the key types are defined in the calculator package.

essentially when i string them together now, i get 4 of them working and (if all '1's are shifted in) it seems to keep showing the last four digits of the number that would be displayed but the output of the fourth unit never goes high and thereofre the input of the fith is always low. hence the stop.

the code below is the definition of the chain.

--------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.calculator_package.ALL;
-- Uncomment the following lines to use the declarations that are
-- provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Converter is
port (BitIN : in std_logic;
clk : in std_logic;
rst : in std_logic;
init : in std_logic;
Output0 : out key_type;
Output1 : out key_type;
Output2 : out key_type;
Output3 : out key_type;
Output4 : out key_type;
Output5 : out key_type;
Output6 : out key_type;
Output7 : out key_type;
Output8 : out key_type;
Output9 : out key_type
);
end Converter;

architecture Structural of Converter is

component SerBCDBin is
Port ( MODin : in std_logic;
clk : in std_logic;
init : in std_logic;
rst : in std_logic;
MODout : out std_logic;
DigitOut : out key_type
);
end component;




--signal Output_int : std_logic_vector (31 downto 0);
signal ModJoin1, ModJoin2, ModJoin3, ModJoin4, ModJoin5, ModJoin6, ModJoin7, ModJoin8, ModJoin9, ModJoin10 : std_logic;

begin

BCDConv0: SerBCDBin port map (MODin => ModJoin1, MODOut => ModJoin10, clk => clk, init => init, rst => rst, DigitOut => Output0);

BCDConv1: SerBCDBin port map (MODin => ModJoin2, MODOut => ModJoin1, clk => clk, init => init, rst => rst, DigitOut => Output1);

BCDConv2: SerBCDBin port map (MODin => ModJoin3, MODOut => ModJoin2, clk => clk, init => init, rst => rst, DigitOut => Output2);

BCDConv3: SerBCDBin port map (MODin => ModJoin4, MODOut => ModJoin3, clk => clk, init => init, rst => rst, DigitOut => Output3);

BCDConv4: SerBCDBin port map (MODin => ModJoin5, MODOut => ModJoin4, clk => clk, init => init, rst => rst, DigitOut => Output4);

BCDConv5: SerBCDBin port map (MODin => ModJoin6, MODOut => ModJoin5, clk => clk, init => init, rst => rst, DigitOut => Output5);

BCDConv6: SerBCDBin port map (MODin => ModJoin7, MODOut => ModJoin6, clk => clk, init => init, rst => rst, DigitOut => Output6);

BCDConv7: SerBCDBin port map (MODin => ModJoin8, MODOut => ModJoin7, clk => clk, init => init, rst => rst, DigitOut => Output7);

BCDConv8: SerBCDBin port map (MODin => ModJoin9, MODOut => ModJoin8, clk => clk, init => init, rst => rst, DigitOut => Output8);

BCDConv9: SerBCDBin port map (MODin => BitIN, MODOut => ModJoin9, clk => clk, init => init, rst => rst, DigitOut => Output9);
end Structural;

------------------------

do you have any idea what could be causing this? it is still causing me a great deal of dificulty in getting it right.

any help is greatly apreciated. sorr for the huge trail of post before this one, but i cant delete them (i dont think).

cheers
mynci
 
this logic is completely different, did you draw up a karnaugh map and figure out a different way to do it yourself?

Probably a good idea since the xilinx document is not very clear.

taking that into consideration I looked at the xilinx implementation again and i realised that the greater than equal to 5 is combinatorial logic and not clocked. that makes your implementation correct, although you have not followed xilinx'es logic.

I think your code should be:

process (clk)

begin

if (clk'event) and clk = '1' then
if en = '1' then

if rst = '1' then
Q <= "0000";
else

if modout = '1' then
Q(3) <= Q(3) and Q(0);
Q(2) <= Q(0) xnor Q(1);
Q(1) <= not Q(0);
Q(0) <= MODin;
else
Q(3 downto 1) <= Q(2 downto 0);
Q(0) <= MODin;
end if; --modtest for 5 or greater
end if;--en
end if; --rst
end if; --clk
end process;

modout <= '1' when q >= "0101" else '0';

of course you can do the modout in a process with the init also like you did.

that code seems to work for me, although my test vector was just all 1's... but it correctly counted up

so try with that logic and see how things go.

--
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top