Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Pipelined MAC
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
count_enable
Делаю простенькое ALU на операции типа О=О+(А*В), О=С+(А*В) которое должно синтезироваться в Xilinxoвый DSP48. Код довольно стандартный, входящие сигналы и выходящий имеют по регистру. Синтезатор мне пишет: "Xst:2385 - HDL ADVISOR - You can improve the performance of the multiplier alu_module/Mmult_i_result_mult0000 by adding 2 register level(s)." Ну и скорость удручающая.. Где именно надо пихнуть эти регистры? А - это вход от BRAM, C-результат от предыдущего DSP48 блока, поэтому важна синхронная скорость BRAM и DSP48. Насколько я знаю, Xilinx специально делает эти блоки максимально совместимыми.

Код
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU is
generic(
        MIN:integer:=-255; -- не всегда совпадает с 2**DATA_WIDTH
        MAX:integer:=255;
        DATA_WIDTH:integer:=9
        );
    Port ( RST : in  STD_LOGIC;
           CLK : in  STD_LOGIC;
           A : in  STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0);
           B : in  STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0);
           C : in  STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0);
           R : out  STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0);
           OPCODE : in  STD_LOGIC_VECTOR (2 downto 0));
end ALU;

architecture Behavioral of ALU is
signal i_result,i_rmul:  signed(DATA_WIDTH*2-1 downto 0);
signal i_A,i_B,i_C: STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0);
begin
process (CLK,RST)
begin
if RST='1' then
        i_result<=(others=>'0');
        i_rmul<=(others=>'0');
        i_A<=(others=>'0');
    i_B<=(others=>'0');
    i_C<=(others=>'0');
else
    if (rising_edge(CLK)) then
    i_A<=A;
    i_B<=B;
    i_C<=C;
        case OPCODE is
            when "000" => --- R=0
                                i_result<=to_signed(0,DATA_WIDTH*2);    
                                i_rmul<=to_signed(0,DATA_WIDTH*2);                                    
            when "001" => --- R=R+(A*B)
                                i_rmul<=(signed(i_A)*signed(i_B));
                                i_result<=resize(i_result+i_rmul,DATA_WIDTH*2);
            when "010" => --- R=C+(A*B)
                                i_rmul<=(signed(i_A)*signed(i_B));
                                i_result<=resize(signed(i_C)+i_rmul,DATA_WIDTH*2);
            when "011" => --- R=R+(A+B)
                                i_rmul<=(signed(i_A)+signed(i_B));
                                i_result<=resize(i_result+i_rmul,DATA_WIDTH*2);
            when "100" => --- R=C+(A+B)
                                i_rmul<=(signed(i_A)+signed(i_B));
                                i_result<=resize(signed(i_C)+i_rmul,DATA_WIDTH*2);
            when others => --- default do nothing
                                i_result<=i_result;
                                i_rmul<=    i_rmul;
        end case;
    end if;
end if;

if i_result<MIN then R <=std_logic_vector(to_signed(MIN,DATA_WIDTH));
    elsif i_result>MAX then R <=std_logic_vector(to_signed(MAX,DATA_WIDTH));
    else R<=std_logic_vector(i_result(DATA_WIDTH-1 downto 0));
end if;

end process;
end Behavioral;
serjj
Объявите DSP48 явно через добавление макрофункции (через Logicore или вручную) и описывайте задержки через соответствующие параметры и режим работы через шину OPMODE дсп слайса. У вас я вижу большой мультиплексор, в котором большой объем умножений/сложений, ISE/Vivada скорее всего не имплиментирует их как надо, т.к. описано некорректно. Самое надежное - сделать через явное описание. Тогда будет работать строго так как вы напишите, а не так как вас поймет синтезатор.
count_enable
Да нет, ISE14.3 распознаёт DSP48 и в финальном синтезе он есть. Но вместо хотя бы 350+ МГц получаю 185.
serjj
Если я напишу y <= a * b; то да он распознает его, и поставит туда. Но с какими параметрами и дополнительной логикой он его поставит? Вы смотрели в RTL Viewer как он синтезировал ваш код, насколько оптимальным получился синтез? Мне сдается, что часть кода имплиментировалась в DSP48, а часть сделалась на логике, из-за чего у вас и наблюдается падение частоты. У вас Spartan 6? Если да, то 350 МГц заявлены только для DSP48, если сигнал проходит еще и через логику, то максимальная частота будет не больше 220-250 МГц в лучшем случае.
count_enable
Virtex 5, должно быть ок. 550 МГц. К сожалению я не настолько хорош в RTL чтобы понять в чем беда. Переделал по образцу "Sequential Complex Multipliers HDL Coding Techniques" из XST UG, частота поднялась вдвое. Но вот понять в чём беда - не понял sad.gif.
serjj
Выложите здесь код, как он выглядет теперь, пожалуйста, что бы тема была наглядна.
count_enable
Подумал и решил что операция типа A+B+C мне не особо и нужна, а если очень надо то можно ее сконструировать из МАСов.

Код
--
-- Sequential Complex Multiplier
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity alu_pipelined is
generic(DATA_WIDTH:positive:=18;
        MAX:integer :=255;
        MIN:integer :=-255;
        RES_WIDTH:positive:=48);
port(
            CLK:in std_logic;
            RST:in std_logic;
            A:in signed(DATA_WIDTH-1 downto 0);
            B:in signed(DATA_WIDTH-1 downto 0);
            C:in signed(DATA_WIDTH-1 downto 0);
            OPCODE:in std_logic_vector(1 downto 0);
            RES:out signed(DATA_WIDTH-1 downto 0)
            );
end alu_pipelined;
architecture beh of alu_pipelined is
constant P_WIDTH: integer:=DATA_WIDTH+DATA_WIDTH;
signal oper_load0: std_logic:='0';
signal oper_addsub0: std_logic:='0';
signal p1: signed(P_WIDTH-1 downto 0):=(others=>'0');
signal oper_load1: std_logic:='0';
signal oper_addsub1: std_logic:='0';
signal res0, res1: signed(RES_WIDTH-1 downto 0);
begin
process (clk)
variable acc: signed(RES_WIDTH-1 downto 0);
begin
if rising_edge(clk) then
    if RST='1' then
        acc:=(others=>'0');
        res0<=(others=>'0');
        p1<=(others=>'0');
    else
        oper_load0<= OPCODE(1);
        oper_addsub0 <= OPCODE(0);
        p1 <= A*B;
        oper_load1<= oper_load0;
        oper_addsub1 <= oper_addsub0;
            if (oper_load1='1') then
                acc := res0;
            else
                acc := resize(signed(C),RES_WIDTH);
            end if;
            if (oper_addsub1='1') then
                res0 <= acc-p1;
            else
                res0 <= acc+p1;
            end if;
    end if;
end if;
            if res0>MAX then res1<=to_signed(MAX,RES_WIDTH);
            elsif res0<MIN then res1<=to_signed(MIN,RES_WIDTH);
            else res1<=res0;
            end if;
end process;
RES <= resize(res1,DATA_WIDTH);
end architecture;
RobFPGA
Приветствую!

Если хотите чтобы синтезатор автоматом пиплайнл регистры в умножитель и пытался впихнуть все в DSP48 блоки то используйте только синхронный reset! (ну или вообще не используйте - для потока данных это не столь обязательно)!

Успехов! Rob.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.