Eine Umwandlung von BCD nach Binär ist eigentlich recht einfach: man multipliziert jede BCD-Stelle mit ihrem dezimalen Stellenwert und summiert das Ganze dann auf. So ergibt sich z.B. folgende Rechnung:
2173(bcd) = 2*1000 + 1*100 + 7*10 + 3*1 = 2173(dez) = 00001000_01111101(bin) = 087d(hex)
Kurzer Einwurf: hier dürfte jedem auffallen, dass 2073(bcd) = 2073(dez) ist. Und das ist ja auch logisch, weil "BCD" ausgeschrieben "Binär codiertes Dezimalsystem" heißt.
Soll nun die obige Rechnung aber in ein FPGA, dann ist es ziemlich ressourcenfressend, wenn die komplette Rechnung kombinatorisch erledigt werden muss. In diesem einfachen Fall oben wären schon 4 Multiplizierer und 4 Addierer nötig.
Sinnvoller ist daher, die Wandlung schrittweise durchzuführen und pro BCD-Stelle einen Takt aufzuwenden. Dazu kann man die obige Rechnung so umstellen:
2173(bcd) = (((2)*10 + 1)*10 + 7)*10) + 3 = 2173(dez) = 00001000_01111101(bin) = 087d(hex)
Man sieht hier, dass pro Schritt immer nur die selbe und vor allem nur eine einzige Multiplikation nötig ist. Zusammen mit einer FSM basierend auf dem Index der Dezimalstelle könnte das dann so umgesetzt werden:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity BCD2BIN is Generic ( width : integer := 4 ); Port ( BCD : in STD_LOGIC_VECTOR (width*4-1 downto 0); BIN : out STD_LOGIC_VECTOR (width*4-1 downto 0); Start : in STD_LOGIC; Idle : out STD_LOGIC; Clk : in STD_LOGIC); end BCD2BIN; architecture Behavioral of BCD2BIN is signal idx : integer range 0 to width-1 := 0; -- 0 = idle signal tmp : unsigned (width*4-1 downto 0); begin process begin wait until rising_edge(Clk); if (idx = 0) then if (start='1') then tmp <= (others=>'0'); tmp(3 downto 0) <= unsigned(BCD(width*4-1 downto width*4-4)); idx <= width-1; end if; else tmp <= resize(tmp*10 + unsigned(BCD(idx*4-1 downto idx*4-4)),tmp'length); idx <= idx-1; end if; end process; BIN <= std_logic_vector(tmp); Idle <= '1' when idx=0 else '0'; end Behavioral;
Und hier eine kleine Testbench mit der passenden Waveform:
LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY tb_BCD2BIN IS END tb_BCD2BIN; ARCHITECTURE behavior OF tb_BCD2BIN IS COMPONENT BCD2BIN PORT( BCD : IN std_logic_vector(15 downto 0); BIN : OUT std_logic_vector(15 downto 0); Start : IN std_logic; Idle : OUT std_logic; Clk : IN std_logic ); END COMPONENT; --Inputs signal BCD : std_logic_vector(15 downto 0) := (others => '0'); signal Start : std_logic := '0'; signal Clk : std_logic := '0'; --Outputs signal BIN : std_logic_vector(15 downto 0); signal Idle : std_logic; -- Clock period definitions constant Clk_period : time := 10 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut: BCD2BIN PORT MAP ( BCD => BCD, BIN => BIN, Start => Start, Idle => Idle, Clk => Clk ); -- Clock process definitions Clk_process :process begin Clk <= '0'; wait for Clk_period/2; Clk <= '1'; wait for Clk_period/2; end process; -- Stimulus process stim_proc: process begin BCD <= x"2173"; wait for 30 ns; start <= '1'; wait for 30 ns; start <= '0'; wait until Idle='1'; wait for 130 ns; BCD <= x"1023"; start <= '1'; wait for 30 ns; start <= '0'; wait until Idle='1'; wait for 130 ns; BCD <= x"1024"; wait for 30 ns; start <= '1'; wait for 30 ns; start <= '0'; wait until Idle='1'; wait for 130 ns; BCD <= x"9999"; wait for 30 ns; start <= '1'; wait for 30 ns; start <= '0'; wait until Idle='1'; wait for 130 ns; BCD <= x"0000"; wait for 30 ns; start <= '1'; wait for 30 ns; start <= '0'; wait until Idle='1'; wait for 130 ns; wait; end process; END;
Das Ergebnis BIN ist einmal dezimal und zudem binär dargestellt.
Aber es gibt immer noch Verbesserungspotential. Basierend auf der Formel
10x + y = 8x + 2x + y
kann diese Multiplikation
tmp <= resize(tmp*10 + unsigned(BCD(idx*4-1 downto idx*4-4)),tmp'length);
durch eine Formelumstellung mit einer zusätzlichen Addition ersetzt werden:
tmp <= resize(tmp*8 + tmp*2 + unsigned(BCD(idx*4-1 downto idx*4-4)),tmp'length);
Der Trick dabei: der Synthesizer erkennt, dass tmp*8 und tmp*2 keine wirklichen Multiplikationen sind, und kann diese Operationen durch ein simples Umverdrahten erledigen. Kurz: es ist kein Multiplizierer nötig, das Design kann schneller getaktet werden...