Перейти к содержанию
    

тактовый умножитель VHDL

День добрый, уважаемые форумчане. Я новенький в VHDL, и первое задание мое было это восьмиразрядный тактовый умножитель . Причем не банальным способом где a*b, а иным. Немного поискав информации в интернете я нашел способ, получил умножитель в виде счетчика с регистром сдвига. В общем вот код.

 

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_unsigned.all;

entity test is
    port( 
    clk, r: in std_logic;
    a : in std_logic_vector(7 downto 0);
    b : in std_logic_vector(7 downto 0);
    p : out std_logic_vector(15 downto 0)
    );
    
end test;

--}} End of automatically maintained section

architecture test of test is 
begin
process(clk,r,a,b)
    variable pv,bp: std_logic_vector(15 downto 0);
    begin          
        pv:= "0000000000000000";
        bp:= "00000000" & b;
        if r='1' then 
            pv:="0000000000000000";
            p<=pv;
        else
        if clk'event and clk = '1' then
        for i in 0 to 7 loop
                if a(i) = '1' then
                pv:= pv+bp;     
                p<=pv;
            end if;
            bp:= bp(14 downto 0) & '0';
        end loop;
        end if;     
        end if;
        end process;
end test;

 

а вот результат моделирования.

 

14072020.png

 

Как видите все работает. Но возникает вопрос. Почему он выдает результат сразу за 1 такт, а не за 8 тактов как должно быть? ведь каждое начало цикла должно входить в 1 такт. а тут сразу весь цикл в такт входит. Но мне нужен тактовый умножитель, чтобы за каждый такт он делал сложение pv с bp и последующим сдвигом влево. Подскажите как сделать так чтобы результат умножения был за 8 тактов а не за 1. Если есть возможность, желательно подскажите на примере, так как я начинающий в этом деле на словах могу не понять. Спасибо.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

День добрый, уважаемые форумчане. Спасибо.

еще это можете посмотреть

+ иное описание (при реализации в "лоб" просидает тактовая частота (получается не высокой), т.е. как i_ma* i_mb)

 

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

entity mult_pipe is
port ( 
  i_clk      : in  std_logic;
  i_rstb     : in  std_logic;
  i_ma       : in  std_logic_vector(34 downto 0);
  i_mb       : in  std_logic_vector(34 downto 0);
  o_m        : out std_logic_vector(69 downto 0));
end mult_pipe;

architecture rtl of mult_pipe is
-- A[34:17] x 2^17 +A[16:0]) x (B[34:17] x 2^17 +B[16:0]) =
-- A[34:17] x B[34:17] x2^34 +(A[34:17] x B[16:0] + A[16:0] x B[34:17] )x2^17 + A[16:0] x B[16:0]

type p_operand_hi is array(0 to 3) of signed(17 downto 0);
type p_operand_lo is array(0 to 3) of signed(16 downto 0);
signal p_ma_hi       : p_operand_hi;
signal p_ma_lo       : p_operand_lo;
signal p_mb_hi       : p_operand_hi;
signal p_mb_lo       : p_operand_lo;

signal r_p1          : signed(35 downto 0);  -- 18x18 => 36 bit (34 + 2 sgn bit)
signal r_p2          : signed(35 downto 0);  -- 18x18 => 36 bit (35 + 1 sgn bit)
signal r_p3          : signed(35 downto 0);  -- 18x18 => 36 bit (35 + 1 sgn bit)
signal r_p4          : signed(35 downto 0);  -- 18x18 => 36 bit

signal r_m1          : signed(35 downto 0);  -- 18x18 => 36 bit (34 + 2 sgn bit)
signal r_m2          : signed(35 downto 0);  -- 18x18 => 36 bit (35 + 1 sgn bit)
signal r_m3          : signed(35 downto 0);  -- 18x18 => 36 bit (35 + 1 sgn bit)
signal r_m4          : signed(35 downto 0);  -- 18x18 => 36 bit

signal p_m1          : p_operand_lo;  -- delay compensation
signal p_m3          : signed(16 downto 0);  -- delay compensation

begin

o_m(69 downto 34)  <= std_logic_vector(r_m4(35 downto 0));
o_m(33 downto 17)  <= std_logic_vector(p_m3);
o_m(16 downto  0)  <= std_logic_vector(p_m1(2));

p_mult : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    p_ma_hi       <= (others=>(others=>'0'));
    p_ma_lo       <= (others=>(others=>'0'));
    p_mb_hi       <= (others=>(others=>'0'));
    p_mb_lo       <= (others=>(others=>'0'));
    p_m1          <= (others=>(others=>'0'));
    p_m3          <= (others=>'0');

    r_m1          <= (others=>'0');
    r_m2          <= (others=>'0');
    r_m3          <= (others=>'0');
    r_m4          <= (others=>'0');
    p_m1          <= (others=>(others=>'0'));
    p_m3          <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    p_ma_hi       <= signed(i_ma(34 downto 17))&p_ma_hi(0 to p_ma_hi'length-2);
    p_ma_lo       <= signed(i_ma(16 downto  0))&p_ma_lo(0 to p_ma_lo'length-2);
    p_mb_hi       <= signed(i_mb(34 downto 17))&p_mb_hi(0 to p_mb_hi'length-2);
    p_mb_lo       <= signed(i_mb(16 downto  0))&p_mb_lo(0 to p_mb_lo'length-2);
    p_m1          <= r_m1(16 downto 0)&p_m1(0 to p_m1'length-2);
    p_m3          <= r_m3(16 downto 0);

    r_p1          <= signed('0'&p_ma_lo(0)) * signed('0'&p_mb_lo(0));
    r_p2          <= signed('0'&p_ma_lo(1)) * p_mb_hi(1);
    r_p3          <= p_ma_hi(2) * signed('0'&p_mb_lo(2));
    r_p4          <= p_ma_hi(3) * p_mb_hi(3);

    r_m1          <= r_p1;
    r_m2          <= r_p2 + r_m1(34 downto 17);
    r_m3          <= r_p3 + r_m2;
    r_m4          <= r_p4 + r_m3(35 downto 17);
  end if;
end process p_mult;

end rtl;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если смотреть на код, то тут просто в лоб a*b ) чего мне не нужно. подскажите, если вы знаете, как сделать так, чтобы мой умножитель делал каждое действие сложения по такту. наверное нужен особенный клок? вот я этого понять не могу. если просто тупо убрать цикл и попробовать прописать все условия if a(0)='1' ..... if a(1)='1'.... все равно он мне все делает за 1 такт. я не знаю как сделать чтобы каждое действие (pv+ bp и сдвиг bp влево) делалось за 1 такт.

Изменено пользователем artyombn

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

подскажите, если вы знаете, как сделать так

Студентов, которым готовый код нужен, тут не очень любят,

а если хотите разобраться, то другое дело.

 

loop надо убрать.

Вместо этого инкрементируйте i (1 раз за такт clk, есесно :-)

и в зависимости от его значения что-то делайте.

 

И советую избавиться от переменных (используйте только сигналы),

а то соседство блокирующих и неблокирующих назначений это для начинающего верный путь запутаться и ничего не понять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

loop надо убрать.

Вместо этого инкрементируйте i (1 раз за такт clk, есесно :-)

и в зависимости от его значения что-то делайте.

 

И советую избавиться от переменных (используйте только сигналы),

а то соседство блокирующих и неблокирующих назначений это для начинающего верный путь запутаться и ничего не понять.

 

loop убрал. инкрементирую i 1 раз за такт. возникает ряд вопросов. почему bp прыгает, сначала как полагается, оно равно 11, затем по единице clk становится 22 (тут произошел сдвиг влево), а затем по спаду оно становится равно опять 11. почему? оно ведь перезаписалось, и до следующего такта не должна меняться. из-за этого оно всегда будет меняться с 11 до 22. почему это условие

if a(i) = '1' then
                pv<= pv+bp;     
            end if;

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

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_unsigned.all;
use IEEE.NUMERIC_STD.all;

entity test is
    port( 
    clk, r: in std_logic;
    a : in std_logic_vector(7 downto 0);
    b : in std_logic_vector(7 downto 0);
    p : out std_logic_vector(15 downto 0)
    );
    
end test;

--}} End of automatically maintained section

architecture test of test is 
signal pv: std_logic_vector(15 downto 0):=(others => '0'); 
signal bp: std_logic_vector(15 downto 0); 
signal i : integer range 0 to 8;
begin
process(clk)
    begin          
        bp<= "00000000" & b;  
        if r='1' then 
            pv<="0000000000000000";
            p<=pv;    
            i <= 0;
        else
        if (clk'event and clk = '1' and not(i=8)) then    
            if a(i) = '1' then
                pv<= pv+bp;     
            end if;
            bp<=bp(14 downto 0) & '0';    
            i<=i+1;
            p<=pv;
        end if;     
        end if;
        end process;
end test;

14033800.png

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а затем по спаду оно становится равно опять 11. почему?

Это происходит из-за верхней строчки bp<= "00000000" & b;

У неё нет никаких условий, поэтому она срабатывает при любом изменении clk.

Её нужно убрать, а как производить первоначальную загрузку bp — подумайте. Может быть стоит проверять условие i = 0 и тогда что-то делать?

 

and not(i=8) тоже нужно убрать, так не пишут.

 

 

почему это условие работает как цикл в одном такте импульса? я не понимаю почему такое банальное описание приводит к таким результатам.

Не понял вопроса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это происходит из-за верхней строчки bp<= "00000000" & b;

У неё нет никаких условий, поэтому она срабатывает при любом изменении clk.

Её нужно убрать, а как производить первоначальную загрузку bp — подумайте. Может быть стоит проверять условие i = 0 и тогда что-то делать?

 

and not(i=8) тоже нужно убрать, так не пишут.

 

таким способом записать bp не получается:

signal bp: std_logic_vector(15 downto 0):="00000000" & b;

поэтому создал переменную load и сделал условие.

if load = '1' then
        bp<= "00000000" & b;
        i<=0;
        end if;

теперь возникают 2 вопроса. как избавиться от проскока значений bp=22 и i=1, которые срабатывают в условии при clk=1? и почему срабатывает условие if a(i)='1' , при i=1 (где a(1)=0) . т.е. мы наблюдаем что при i=1 pv=bp, хотя при i=1 по коду это условие не должно выполняться и просто должен произойти сдвиг bp.

 

14071740.png

 

хотя я нашел выход)

14069680.png

 

просто прописал условие в нужном месте

begin           
        if r='1' then 
            pv<="0000000000000000";
            p<=pv;    
            i <= 0;
        else
            if load = '1' then
        bp<= "00000000" & b; 
        i<=0;
        else
        if (clk'event and clk = '1' and not(i=8)) then    
            if a(i) = '1' then
                pv<= pv+bp;     
            end if;
            bp<=bp(14 downto 0) & '0';    
            i<=i+1;
            p<=pv;
            end if;
        end if;     
        end if;

 

почему нельзя писать not(i=8) при разводке в леонардо это скажется? и как остановить расчет иначе когда i достигнет 8?

Изменено пользователем artyombn

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

signal bp: std_logic_vector(15 downto 0):="00000000" & b;

Так и не нужно.

 

поэтому создал переменную load и сделал условие.

А вот это уже правильно. Поскоку устройство не может принимать данные в каждом такте,

то в перспективе оно должно сигнализировать наружу о своей готовности, готовности результата,

а "наружа" должна сигнализировать загрузку новых данных (ваш load).

 

теперь возникают 2 вопроса.

Как сказал Мюллер, вы уже на полпути в успеху :-))))

А я ухожу, вернусь поздно вечером.

 

почему нельзя писать not(i=8) при разводке в леонардо это скажется? и как остановить расчет иначе когда i достигнет 8?

Ну не делают так.

Когда расчёт закончен, нужно сигнализировать наружу о готовности результата и ждать следующего load.

А пытаться остановить клок и ничё не делать нельзя.

Ну и вообще, до хорошего стиля программирования мы ещё не дошли.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

избавился от not(i=8)

if load = '1' then
        bp<= "00000000" & b; 
        else
        if (clk'event and clk = '1') then    
            if a(i) = '1' then
                pv<= pv+bp;        
            end if;
            bp<=bp(14 downto 0) & '0';    
            i<=i+1; 
            if i<=8 then
            p<=pv;
            end if;
            end if;

но я не знаю как остановить дальнейшее увеличение i.

 

и ещё такой вопрос. если у нас load не доходит до фронта первого такта, то задержка выхода p составляет 1 такт. если load доходит или лежит в области первого такта, то задержка на выходе p составляет 2 такта. есть ли возможность избавиться от задержки?

Изменено пользователем artyombn

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но я не знаю как остановить дальнейшее увеличение i.

Да просто поставить условие. Если меньше чего-то, тогда инкрементируем.

 

и ещё такой вопрос. если у нас load не доходит до фронта первого такта

Как не доходит? Тогда данные не загрузятся (если только случайно). Он должен стоять одновременно с данными.

 

есть ли возможность избавиться от задержки?

p<=pv нужно вообще вынести из процесса, один такт уйдёт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да просто поставить условие. Если меньше чего-то, тогда инкрементируем.

да, что-то сглупил в этом моменте.

Как не доходит? Тогда данные не загрузятся (если только случайно). Он должен стоять одновременно с данными.

вот результат если load не будет доходить до clk 14044934.png

а вот результат если будет 14029574.png

разницу не вижу. вижу задержку по такту. с одной стороны хорошо когда i на первом клоке равно 0, но тогда результат будет даже не за 9 тактов, а за 10. что ещё хуже. а нужно результат вообще за 8 тактов.

p<=pv нужно вообще вынести из процесса, один такт уйдёт.

вынес из процесса. он мне показывает неопределенное состояние. 14074648.png

скорее всего потому что pv каждый раз меняет свое значение, а я прошу вывести общую p<=pv. поэтому он и не понимает какую нужно вывести. получается просто вынести pv из процесса не получится

Изменено пользователем artyombn

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проглядел немного что вы там понаписали....

 

Нельзя так писать, у вас лоад асинхронный получился.

 

Шаблон такой:

 

process begin
    wait until clk'event and clk = '1';

    if load = '1'
    then
        что-то
    else
        if i < 8
        then
            if i = 0
            then
                что-то
            end if;

            что-то ещё
        else
            что-то
        end if;
    end if;

end process;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

            if i = 0
            then
                что-то
            end if;

            что-то ещё
        else
            что-то
;

я не понял зачем тут if i=0 ? т.е. мне каждое изменение i описывать? к примеру как я понял:

        if i<8 then     
            if i<=0 then    
            if a(i) = '1' then
                pv<= pv+bp;    
            end if;    
            bp<=bp(14 downto 0) & '0';    
            i<=i+1;    
        else
        if i<=1 then    
            if a(i) = '1' then
                pv<= pv+bp;    
            end if;
            bp<=bp(14 downto 0) & '0';    
            i<=i+1;    
        end if;
        end if;     
        end if;
        end if;

 

и ещё VHDL ругается на "wait until clk'event and clk = '1';" , с непонятной для меня ошибкой:

"# Error: COMP96_0242: testt.vhd : (50, 1): Wait statement in process with explicit sensitivity list is not allowed."

Изменено пользователем artyombn

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я не понял зачем тут if i=0 ? т.е. мне каждое изменение i описывать?

Каждое не нужно, а 0 может быть и нужно.

 

"# Error: COMP96_0242: testt.vhd : (50, 1): Wait statement in process with explicit sensitivity list is not allowed."

Ну так уберите сенситивити лист, я же ясно написал process begin.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вот переписанный код

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_unsigned.all;
use IEEE.NUMERIC_STD.all;

entity test is
    port( 
    clk, r: in std_logic;
    a : in std_logic_vector(7 downto 0);
    b : in std_logic_vector(7 downto 0);
    p : out std_logic_vector(15 downto 0);
    load: in std_logic
    );
    
end test;

--}} End of automatically maintained section

architecture test of test is 
signal pv: std_logic_vector(15 downto 0):=(others => '0'); 
signal bp: std_logic_vector(15 downto 0);
signal i : integer range 0 to 8;
begin     
process
begin  
wait until clk'event and clk = '1';     
        if load = '1' then
        bp<= "00000000" & b; 
        i <= 0;
        else  
            if i<8 then     
            if i<=0 then    
            if a(i) = '1' then
                pv<= pv+bp;    
            end if;    
            bp<=bp(14 downto 0) & '0';    
            i<=i+1;    
        else    
            if a(i) = '1' then
                pv<= pv+bp;    
            end if;
            bp<=bp(14 downto 0) & '0';    
            i<=i+1;    
        end if;
        end if;
        p<=pv;
        end if;
        end process;  
end test;

вот моделирование

14057235.png

изначально он не может понять что такое bp пока не стартанет клок. задать заранее bp мы не можем, ибо без клока ничего вообще происходить не будет. именно поэтому раньше клок у меня шел после лоад, но тогда, как вы сказали, лоад будет действительно ассинхронный.

и почему pv в первый такт не стал равен bp? вроде как это условие выполняется

if i<8 then     
            if i<=0 then    
            if a(i) = '1' then
                pv<= pv+bp;    
            end if;

и должно попасть в первый такт

 

и почему pv в первый такт не стал равен bp? вроде как это условие выполняется
if i<8 then     
            if i<=0 then    
            if a(i) = '1' then
                pv<= pv+bp;    
            end if;

и должно попасть в первый такт

хотя оно попадает, но во второй такт..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...