Forum: FPGA, VHDL & Co. nochmal Problem mit Spartan 3 Multiplier


von TheMason (Gast)


Lesenswert?

Hallo Leute,

ich nochmal. Ich möchte mein Audio-Projekt in einen Spartan3 400 Tq144 
reinquetschen.
Ich bekomme es nur hin wenn ich alle optimierungen (area) an habe und 
große teile des designs weg lasse.
Das problem ist die MAC-Einheit. Hier mal der Code :

  ---------------------------------------------
  --
  --   Data Muxers (Input and Coefficient)
  --
  ---------------------------------------------


  --
  -- Muxer for MAC-Input A (Audio-Data) and AMEM-Write-Data
  --

  process (clk, res, sdc_a_data_src, input, sdc_b_rdata, sdc_mac_out)
  begin
    if res = '1' then
      sdc_a_wdata <= (others => '0');
    elsif clk'event and clk = '1' then
      case sdc_a_data_src is
        when "00"    => sdc_a_wdata <= std_logic_vector (input);
        when "01"    => sdc_a_wdata <= sdc_b_rdata;
        when "10"    => sdc_a_wdata <= std_logic_vector 
(sdc_mac_val_32);
        when "11"    => sdc_a_wdata <= (others => '0');
        when others  => sdc_a_wdata <= (others => '0');
      end case;
    end if;
  end process;

  --
  -- Muxer for Output of SDSP Core (MAC-Output or BMEM)
  --

  process (clk, res, sdc_output_src)
  begin
    if res = '1' then
      sdc_toutput <= (others => '0');
    elsif clk'event and clk = '1' then
      case sdc_output_src is
        when "00"   => sdc_toutput <= sdc_mac_out;
        when "01"   => sdc_toutput <= signed (sdc_b_rdata);
        when others => NULL;
      end case;
    end if;
  end process;


  --
  -- Coeff-Muxer (can be CMEM, 1.0, 0.0, -1.0 )
  --

  process (clk, res, sdc_c_rdata, sdc_coeff_routing, sdc_ena_coeff_reg)
  begin
    if res = '1' then
      sdc_mac_coeff <= X"00000000";
    elsif clk'event and clk = '1' then
      if sdc_ena_coeff_reg = '1' then
        case sdc_coeff_routing is
          when "00"   => sdc_mac_coeff <= signed (sdc_c_rdata);
          when "01"   => sdc_mac_coeff <= X"01000000";
          when "10"   => sdc_mac_coeff <= X"00000000";
          when "11"   => sdc_mac_coeff <= X"FFFFFFFF";
          when others => NULL;
        end case;
      end if;
    end if;
  end process;


  ---------------------------------------------
  --
  -- MAC-Unit
  --
  ---------------------------------------------


  --
  -- MAC-Unit itself
  --

  process (clk, res, sdc_ena_macres, sdc_ena_mac, sdc_mac_val)
  begin
    if res = '1' then
      sdc_mac_val   <= (others => '0');
    elsif clk'event and clk = '1' then

      -- Reset Accumulator
      if sdc_ena_macres = '1' then
        sdc_mac_val     <= (others => '0');
        sdc_mac_val_tmp  <= (others => '0');
      end if;

      -- Enable Operation
      if sdc_ena_mac = '1' then
        sdc_mac_val_tmp <= ( signed (sdc_a_wdata) * signed 
(sdc_mac_coeff) );
  --      sdc_mac_val <= sdc_mac_val + ( signed (sdc_a_wdata) * signed 
(sdc_mac_coeff) );
      end if;
      -- Enable Acuumulate
      if sdc_ena_mac_add = '1' then
        sdc_mac_val <= sdc_mac_val + sdc_mac_val_tmp;
      end if;
    end if;
  end process;


  --
  -- Hard-Clipping of 64-Bit Result of MAC-Accumulator
  --
  -- Clipping is done on the bits 55..24 (we have 8 bit headroom at 
multiply)
  --

  process (clk, res, sdc_mac_val)
  begin
    if res = '1' then
    --  sdc_mac_val_32 <= (others => '0');
    elsif clk'event and clk = '1' then
      -- dependend on sign
      if sdc_mac_val (63) = '1' then
        -- check only the 9 highest bits of relevant data
        if std_logic_vector (sdc_mac_val (63 downto 55)) = "111111111" 
then
          -- in range
           sdc_mac_val_32 <= sdc_mac_val (55 downto 24);
        else
          -- out of range
           sdc_mac_val_32 <= X"80000000";
        end if;
      else
        -- check only the 9 highest bits of relevant data
        if std_logic_vector (sdc_mac_val (63 downto 55)) = "000000000" 
then
          -- in range
           sdc_mac_val_32 <= sdc_mac_val (55 downto 24);
        else
          -- out of range
           sdc_mac_val_32 <= X"7fffffff";
        end if;
      end if;
    end if;
  end process;



--  process (clk, res, sdc_mac_val)
--  begin
--    if res = '1' then
--      sdc_mac_val_32 <= (others => '0');
--    elsif clk'event and clk = '1' then
--      sdc_mac_val_32 <= sdc_mac_val (55 downto 24) when 
(std_logic_vector (sdc_mac_val (63 downto 55)) = "111111111") else
--                        sdc_mac_val (55 downto 24) when 
(std_logic_vector (sdc_mac_val (63 downto 55)) = "000000000") else
--                        X"80000000"                when sdc_mac_val 
(63) = '1' else
--                        X"7fffffff";
--    end if;
--  end process;

  --
  -- Hard-Clipping of 32-Bit Result to 24 Bit Result (for I2S-Output is 
24 Bit Wide, may add an Enable signal to give mre control over clipping)
  --

  process (clk, res, sdc_mac_val_32)
  begin
    if res = '1' then
      sdc_mac_out <= (others => '0');
    elsif clk'event and clk = '1' then
      -- dependend on sign
      if sdc_mac_val_32 (31) = '1' then
        -- check only the 9 highest bits of relevant data
        if std_logic_vector (sdc_mac_val_32 (31 downto 23)) = 
"111111111" then
          -- in range
           sdc_mac_out <= sdc_mac_val_32;
        else
          -- out of range
           sdc_mac_out <= X"ff800000";
        end if;
      else
        -- check only the 9 highest bits of relevant data
        if std_logic_vector (sdc_mac_val_32 (31 downto 23)) = 
"000000000" then
          -- in range
           sdc_mac_out <= sdc_mac_val_32;
        else
          -- out of range
           sdc_mac_out <= X"007fffff";
        end if;
      end if;
    end if;
  end process;

Das ist das Herzstück meines DAPs.
Und genau im Multiplizierer (+Addierer) liegt das Problem.
Je nachdem welche Teile ich weglasse (oder auch nicht) lässt sich das 
Projekt synthetisieren (oder eben auch nicht).
Wenn es nicht geht meldet mir ISE "Congestion on subnet ...."
Also Verstopfung mangels interconnects.
Welche Möglichkeiten habe ich außer einem Core-Generator zu bemühen ?
Ich möchte das ganze design nicht unbedingt neumachen müssen, und das 
Hauptproblem ist die MAC-Einheit.
Wie kann man den Multiplizierer verbessern (Pipelining ?) ? Im Moment 
bekomme ich noch keine Simulation mit dem ISE hin (bin zu doof dafür) um 
Vergleichen zu können.
Wäre schön wenn mir jemand helfen könnte.

Das Implementierungs Problem habe ich nur auf dem S3-400 auf dem S3-1000 
nicht (anscheinend genug platz) ...

Gruß
Rene

von Kest (Gast)


Lesenswert?

Hallo,

wozu brauchst Du enable Signale für Multiplikation und Addition? Lass 
sie doch immer machen, was sie sollen. Du weist dann genau, wie lange 
sie dauern, von daher sollte es doch kein Problem sein... Damit hättest 
Du schon mal die Enable-Signale eingespart.

Als nächstes würde ich reset-Path rausnehmen -- das sind auch Muxer (es 
kann zwar verschieden implementiert sein, aber da sparst Du Logic 
Cells). Den synchronen Reset würde ich überarbeiten, so wie es da steht 
ist einfach unüblich (denke ich)

  -- Reset Accumulator
      if sdc_ena_macres = '1' then
        sdc_mac_val     <= (others => '0');
        sdc_mac_val_tmp  <= (others => '0');
      end if;

      -- Enable Operation
      if sdc_ena_mac = '1' then
        sdc_mac_val_tmp <= ( signed (sdc_a_wdata) 
*signed(sdc_mac_coeff));
      end if;

Was passiert, wenn sdc_ena_carres='1' und sdc_ena_mac='1' ist? Ist 
einfach unsauber und dann musst Du halt wissen, welche Zuweisung als 
letzte steht -- würde ich so nicht machen.

Und noch eine "Anregung": wenn Du nur mit audio arbeitest, glaube ich 
nicht, dass Du sowas "Großes" brauchst, vielleicht tut es auch was 
serielles? Die Multiplikation in Hardware ist zwar schön und gut, ist 
aber räumlich sehr eingeschränkt (z.B. nur nah an BlockRams). Dann ist 
es auch klar, dass es irgendwann mal zu Routing-problemen kommen kann.

Machs gut,

Kest

von TheMason (Gast)


Lesenswert?

hallo kest,

erstmal danke für die antwort und die tipps.

>vielleicht tut es auch was serielles?

an sowas dachte ich auch schon, aber ... wie macht man sowas genau ?

gruß
rene

von TheMason (Gast)


Lesenswert?

ich nochmal ...

habe noch etwas gebaut und gebastelt und bin dabei (durch hinweise von 
kest) auf die idee gekommen u.a. das 2 fache hardclipping durch ein 
einfaches zu ersetzen, das ganze als kombinatorische logik um mir somit 
in dem kritischen pfad etwas luft zu machen.
außerdem habe ich die info (multiplizierer liegen nahe blockrams)
verwurstet und im gesamten design den lese-daten bus für die blockrams 
eingespart. plus noch ein paar anderere kleinere optimierungen und 
"weglassen". es hatte erfolg ...
ich kann (fast) das komplette ursprüngliche design jetzt sogar in einen 
spartan3 200 unterbringen und es läuft. freu freu :-)
jetzt werd ich mich an den synth machen :-))

nun meine zwei erkenntnisse :
dadurch das das design trotz routingprobleme selbst auf einem kleineren 
fpga lauffähig ist denke ich, das ich "nur" die mac-einheit tauschen muß 
(und den micro-code anpassen muß) und schon dürfte das routing-problem 
umgangen sein. außerdem dürfte (im falle eines seriellen 
multiplizierers) die effektive geschwindigkeit des designs steigen (die 
4 multiplizierer ziehen durch das routing die mögliche 
meximalgeschwindigkeit des systems runter). bei erweiterung des designs 
(und verwendung eines 400'er spartans) dürfte/müsste/sollte es weniger 
implementierungsprobleme durch "enstpannteres routing" geben.
sehe ich die o.g. punkte richtig ? (von dem bischen was man zu den infos 
sagen kann))

dank nochmal an kest.

gruß
rene

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.