Преобразование 8-битного двоичного числа в BCD в VHDL

Алгоритм известен, вы делаете 8 сдвигов влево и после каждого сдвига проверяете единицы, десятки или сотни бит (по 4). Если их больше 4, вы добавляете 3 в группу и так далее...

Вот решение, основанное на процессе, которое не работает. Он скомпилируется, но результат будет не таким, как я хотел. Есть мысли в чем может быть проблема?

library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;

entity hex2bcd is
    port ( hex_in  : in  std_logic_vector (7 downto 0) ;
           bcd_hun : out std_logic_vector (3 downto 0) ;
           bcd_ten : out std_logic_vector (3 downto 0) ;
           bcd_uni : out std_logic_vector (3 downto 0) ) ;
end hex2bcd ;

architecture arc_hex2bcd of hex2bcd is
begin
    process ( hex_in )
        variable hex_src : std_logic_vector (7 downto 0) ;
        variable bcd     : std_logic_vector (11 downto 0) ;
    begin
        hex_src := hex_in ;
        bcd     := (others => '0') ;

        for i in 0 to 7 loop
            bcd := bcd(11 downto 1) & hex_src(7) ; -- shift bcd + 1 new entry
            hex_src := hex_src(7 downto 1) & '0' ; -- shift src + pad with 0

            if bcd(3 downto 0) > "0100" then
                bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
            end if ;
            if bcd(7 downto 4) > "0100" then
                bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
            end if ;
            if bcd(11 downto 8) > "0100" then
                bcd(11 downto 8) := bcd(11 downto 8) + "0011" ;
            end if ;
        end loop ;

        bcd_hun <= bcd(11 downto 8) ;
        bcd_ten <= bcd(7  downto 4) ;
        bcd_uni <= bcd(3  downto 0) ;

    end process ;
end arc_hex2bcd ;

person user34920    schedule 26.05.2014    source источник


Ответы (4)


Комментарии стали слишком длинными.

Рассмотрим следующую блок-схему:

блок-схема bin8bcd

Это представляет собой развернутый цикл (for i in 0 to 7 loop) и показывает, что добавление +3 не происходит до i = 2 для цифры BCD LS и добавление +3 не происходит до i = 5 для средней цифры BCD, а корректировка цифры MS BCD не происходит. , который частично состоит из статических нулевых значений.

Это дает нам в общей сложности 7 модулей add3 (представленных прилагаемым оператором if и условным добавлением +3).

Это продемонстрировано в VHDL:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bin8bcd is
    port (
        bin:    in  std_logic_vector (7 downto 0);
        bcd:    out std_logic_vector (11 downto 0)
    );
end entity;

architecture struct of bin8bcd is
    procedure add3 (signal bin: in  std_logic_vector (3 downto 0); 
                    signal bcd: out std_logic_vector (3 downto 0)) is
    variable is_gt_4:  std_logic;
    begin
        is_gt_4 := bin(3) or (bin(2) and (bin(1) or bin(0)));

        if is_gt_4 = '1' then
        -- if to_integer(unsigned (bin)) > 4 then
            bcd <= std_logic_vector(unsigned(bin) + "0011");
        else
            bcd <= bin;
        end if;
    end procedure;

    signal U0bin,U1bin,U2bin,U3bin,U4bin,U5bin,U6bin:
                std_logic_vector (3 downto 0);

    signal U0bcd,U1bcd,U2bcd,U3bcd,U4bcd,U5bcd,U6bcd:
                std_logic_vector (3 downto 0);       
begin
    U0bin <= '0' & bin (7 downto 5);
    U1bin <= U0bcd(2 downto 0) & bin(4);
    U2bin <= U1bcd(2 downto 0) & bin(3);
    U3bin <= U2bcd(2 downto 0) & bin(2);
    U4bin <= U3bcd(2 downto 0) & bin(1);

    U5bin <= '0' & U0bcd(3) & U1bcd(3) & U2bcd(3);
    U6bin <= U5bcd(2 downto 0) & U3bcd(3);

U0: add3(U0bin,U0bcd);

U1: add3(U1bin,U1bcd);

U2: add3(U2bin,U2bcd);

U3: add3(U3bin,U3bcd);

U4: add3(U4bin,U4bcd);

U5: add3(U5bin,U5bcd);

U6: add3(U6bin,U6bcd);

OUTP:
    bcd <= '0' & '0' & U5bcd(3) & U6bcd & U4bcd & bin(0);

end architecture;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bin8bcd_tb is
end entity;

architecture foo of bin8bcd_tb is
    signal bin: std_logic_vector (7 downto 0) := (others => '0');
    -- (initialized to prevent those annoying metavalue reports)

    signal bcd: std_logic_vector (11 downto 0);

begin

DUT:
    entity work.bin8bcd
        port map (
            bin => bin,
            bcd => bcd
        );

STIMULUS:
    process

    begin
        for i in 0 to 255 loop
            bin <= std_logic_vector(to_unsigned(i,8));
            wait for 1 ns;
        end loop;
        wait for 1 ns;
        wait;
    end process;
end architecture;

Это при запуске сопутствующего тестового стенда дает:

bin8bcd_tb png

И если вы прокрутите всю форму сигнала, вы обнаружите, что все выходы двоично-десятичного кода от 001 до 255 присутствуют и учитываются (без отверстий), нигде нет «X» или «U».

Из представления на блок-диаграмме, показывающего i = 7, мы видим, что после последнего сдвига не происходит добавления +3.

Также обратите внимание, что младший бит bcd всегда является младшим битом bin, и что bcd(11) и bcd(10) всегда равны «0».

add3 можно оптимизировать вручную для создания приращения на 3 с помощью логических операторов, чтобы избавиться от любой возможности сообщать о мета-значениях, полученных из bin (а ​​их будет много).

Насколько я могу судить, это представляет собой наиболее оптимизированное представление преобразования 8-битного двоичного кода в 12-битный BCD.

Некоторое время назад я написал программу на C для ввода эспрессо (термин минимизатор):

/*
 * binbcd.c   - generates input to espresso for 8 bit binary
 *         to 12 bit bcd.
 *
 */
#include <stdlib.h>
#include <stdio.h>


int main (argc, argv)
int argc;
char **argv;
{
int binary;
int bit;
char bcd_buff[4];
int digit;
int bcd;

    printf(".i 8\n");
    printf(".o 12\n");

    for (binary = 0; binary < 256; binary++)  {
        for ( bit = 7; bit >= 0; bit--) {
            if ((1 << bit) & binary)
                printf("1");
            else
                printf("0");
        }

        digit = snprintf(bcd_buff,4,"%03d",binary); /* leading zeros */

        if (digit != 3) {
            fprintf(stderr,"%s: binary to string conversion failure, digit = %d\n",
                argv[0],digit);
            exit (-1);
        }

        printf (" ");  /* input to output space */

        for ( digit = 0; digit <= 2; digit++) {
            bcd = bcd_buff[digit] - 0x30;
            for (bit = 3; bit >= 0; bit--) {
                if ((1 << bit) & bcd) 
                    printf("1");
                else
                    printf("0"); 
            }
        }
        /* printf(" %03d",binary); */
        printf("\n");
    }

    printf (".e\n");
    exit (0);

Затем начал ковыряться с промежуточными терминами, что привело вас прямо к тому, что представлено на блок-схеме выше.

И, конечно же, вы можете использовать реальный компонент add3, а также использовать вложенные операторы генерации для подключения всего.

Вы не получите такое же минимизированное аппаратное обеспечение из представления инструкции цикла без ограничения операторов if (2 ‹ i ‹ 7 для младшей двоично-десятичной цифры, 5 ‹ i ‹ 7 для средней двоично-десятичной цифры).

Вы бы хотели, чтобы вспомогательный вложенный оператор генерации предоставлял те же ограничения для укороченного структурного представления.

Версия add3 с логическим оператором показана на странице 5 в формате PDF на слайды университетских лекций для преобразования двоичного кода в двоично-десятичный с использованием двойного dabble, где галочка вперед используется для обозначения отрицания, "+" означает ИЛИ , а Смежность означает И.

Затем add3 выглядит так:

procedure add3 (signal bin: in  std_logic_vector (3 downto 0); 
                signal bcd: out std_logic_vector (3 downto 0)) is

begin

    bcd(3) <=  bin(3) or 
              (bin(2) and bin(0)) or 
              (bin(2) and bin(1));

    bcd(2) <= (bin(3) and bin(0)) or
              (bin(2) and not bin(1) and not bin(0));

    bcd(1) <= (bin(3) and not bin(0)) or
              (not bin(2) and bin(1)) or
              (bin(1) and bin(0));

    bcd(0) <= (bin(3) and not bin(0)) or
              (not bin(3) and not bin(2) and bin(0)) or
              (bin(2) and bin(1) and not bin(0));

end procedure;

Обратите внимание, что это позволит исключить пакет numeric_std (или эквивалентный) из предложения контекста.

Если вы записываете сигналы в терминах И в том же порядке (в данном случае слева направо), дублированные термины И хорошо видны, как и при использовании эспрессо. Нет смысла использовать промежуточные термины AND в реализации FPGA, все они соответствуют LUT именно такими, какие они есть.

ввод эспрессо для add3: .i 4 .o 4 0000 0000 0001 0001 0010 0010 0011 0011 0100 0100 0101 1000 0110 1001 0111 1010 1000 1011 1001 1100 1010 ---- 1011 ---- 1100 ---- 1101 ---- 1110 ---- 1111 ---- .e

И выход эспрессо (espresso -eonset): .i 4 .o 4 .p 8 -100 0100 00-1 0001 --11 0010 -01- 0010 -110 1001 -1-1 1000 1--1 1100 1--0 1011 .e

Если учесть комбинаторную «глубину» преобразования двоичного кода в двоично-десятичный, для FPGA это 6 LUT (6-й вход для чего-то следующего). Это, вероятно, ограничивает тактовую частоту чем-то около 100 МГц, если преобразование происходит за один такт.

Путем конвейерной обработки или использования последовательной логики (цикл с тактовой частотой) вы сможете запускать FPGA с максимальной скоростью при выполнении за 6 тактов.

person Community    schedule 27.05.2014

Появляются как минимум две проблемы:

  • Добавление происходит после смены, а не раньше, как описано в алгоритме Double dabble

  • bcd смена идет bcd(11 downto 1), но должна быть bcd(10 downto 0)

Итак, попробуйте с кодом:

process ( hex_in )
    variable hex_src : std_logic_vector (7 downto 0) ;
    variable bcd     : std_logic_vector (11 downto 0) ;
begin
    hex_src := hex_in ;
    bcd     := (others => '0') ;

    for i in 0 to 7 loop
        if bcd(3 downto 0) > "0100" then
            bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
        end if ;
        if bcd(7 downto 4) > "0100" then
            bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
        end if ;
        if bcd(11 downto 8) > "0100" then
            bcd(11 downto 8) := bcd(11 downto 8) + "0011" ;
        end if ;

        bcd := bcd(10 downto 0) & hex_src(7) ; -- shift bcd + 1 new entry
        hex_src := hex_src(6 downto 0) & '0' ; -- shift src + pad with 0
    end loop ;

    bcd_hun <= bcd(11 downto 8) ;
    bcd_ten <= bcd(7  downto 4) ;
    bcd_uni <= bcd(3  downto 0) ;

end process ;

Однако для реализации могут потребоваться медленные часы...

Основываясь на наблюдениях Дэвида в комментариях, код должен быть оптимизирован для:

process ( hex_in )
    variable hex_src : std_logic_vector (4 downto 0) ;
    variable bcd     : std_logic_vector (11 downto 0) ;
begin
    bcd             := (others => '0') ;
    bcd(2 downto 0) := hex_in(7 downto 5) ;
    hex_src         := hex_in(4 downto 0) ;

    for i in hex_src'range loop
        if bcd(3 downto 0) > "0100" then
            bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
        end if ;
        if bcd(7 downto 4) > "0100" then
            bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
        end if ;
        -- No roll over for hundred digit, since in 0 .. 2

        bcd := bcd(10 downto 0) & hex_src(hex_src'left) ; -- shift bcd + 1 new entry
        hex_src := hex_src(hex_src'left - 1 downto hex_src'right) & '0' ; -- shift src + pad with 0
    end loop ;

    bcd_hun <= bcd(11 downto 8) ;
    bcd_ten <= bcd(7  downto 4) ;
    bcd_uni <= bcd(3  downto 0) ;
end process ;
person Morten Zilmer    schedule 26.05.2014
comment
Сдвиг вектора BCD действительно имел ошибку, однако я выполняю сдвиг перед операторами if, которые проверяют, следует ли добавлять 3. Я протестировал его в симуляторе Quartus, и он отлично работает для 1-го ввода, второй ввод (при изменении ввода) не обновляет вывод. - person user34920; 26.05.2014
comment
hex_src := hex_src(7 до 1) & '0' ; также неправильно, должно быть (6 вниз к 1). Теперь это работает. Хотя я не понимаю, почему. Сдвиг должен происходить перед добавлением. - person user34920; 26.05.2014
comment
Вы, ребята, понимаете, что для ввода 8-битного двоичного значения вам не нужно баловаться с bcd[11 to 8], не так ли? Значение никогда не будет больше 2. Цифра MS bcd свободна. См. страницу 2 https://web.archive.org/web/20120131075956/http://edda.csie.dyu.edu.tw/course/fpga/Binary2BCD.pdf Ваш последний оператор if не нужен, bcd(11) и bcd(10) всегда должны быть «0», нет > "0100". Вы также можете сделать это последовательно за 8 тактов (которые часто могут быть скрыты в зависимости от интервала обновления дисплея). - person ; 27.05.2014
comment
Для приведенного выше оператора цикла никакие dabble не могут возникать до i = 2 для bcd (от 3 до 0) и i = 5 для bcd (от 7 до 4), что можно использовать для уменьшения количества генерируемого оборудования с помощью квалификации оператора if для dabbles. (Ускорение часов). - person ; 27.05.2014
comment
@DavidKoontz - Итак, вы говорите, что я могу делать меньше итераций, потому что до 3 смен в любом случае не может быть числа больше 100, а также что последняя цифра не может превышать 2 из-за 2 ^ 8-1 255, так что это насколько это возможно, а также потому, что я не сдвигаю достаточно раз, чтобы ввести более 2 бит в цифру MSB BCD. Я до сих пор не понимаю, как это работает со сменой после проверок? - person user34920; 27.05.2014
comment
Добавлен оптимизированный код на основе комментариев Дэвида. Сдвиг работает после проверок и дополнений, так как добавление 3 к значению › 4 (›= 5) похоже на добавление 6 к значению ›= 10 после одного сдвига влево (* 2), таким образом, числовое значение перекатывается. от 9 до 0 или более в двоично-десятичном разряде и с переносом к следующему старшему разряду двоично-десятичного числа. - person Morten Zilmer; 27.05.2014

1. вам нужно перевести бит с 10 на 0 в BCD и с 6 на 0 в hex_src для правильного сдвига.

2. после 8-го сдвига значение hex_src, которое вы не должны добавлять дальше, попробуйте ограничить добавление при 7-м сдвиге, вы можете использовать оператор if, чтобы избежать.

  1. после каждого преобразования сбрасывать значение BCD на ноль.

после приведенного выше кода исправления должно работать

person Deepak Kumar    schedule 31.01.2019

В квартус 18.1 лайт работает.

    LIBRARY ieee;                       
USE ieee.std_logic_1164.ALL; 
use ieee.numeric_std.all;  
--converting a 8bit binary number to a 12bit bcd
entity bin2bcd is
port (bin :in std_logic_vector (7 downto 0);
        bcd1 : out std_logic_vector (3 downto 0);
        bcd2 : out std_logic_vector (3 downto 0);
        bcd3 : out std_logic_vector (3 downto 0));
end entity;

architecture rtl of bin2bcd is 
begin
process ( bin )
    variable binx : std_logic_vector (7 downto 0) ;
    variable bcd     : std_logic_vector (11 downto 0) ;
begin
    bcd             := (others => '0') ;
    binx        := bin(7 downto 0) ;

    for i in binx'range loop
        if bcd(3 downto 0) > "0100" then
          bcd(3 downto 0) := std_logic_vector(unsigned( bcd(3 downto 0)) + "0011"); 

        end if ;
        if bcd(7 downto 4) > "0100" then
           bcd(7 downto 4) := std_logic_vector(unsigned( bcd(7 downto 4)) + "0011");    
        end if ;
        bcd := bcd(10 downto 0) & binx(7) ; 
        binx := binx(6 downto 0) & '0' ; 
    end loop ;

    bcd3 <= bcd(11 downto 8) ;
    bcd2 <= bcd(7  downto 4) ;
    bcd1 <= bcd(3  downto 0) ;
end process ;
end architecture;
person qiqi    schedule 23.03.2019