Forum: FPGA, VHDL & Co. Bit Matrix in VHDL


von Hagen (Gast)


Lesenswert?

Hi Leute,

ich bin gerade beim Einstieg in VHDL um CPLD's zu programmieren.
Nutzen tue ich dafür Quartus von Altera.

Bei meinem derzeitigen Übungsprojekt wird der CPLD an einen
Address-/Datenbus angeschlossen. Der CPLD bekommt insgesamt 32 Bytes an
Daten gesendet die dieser intern in einer Matrix a 8*32 Bit speichern
soll. Das Einlesen dieser Matrix muß also über die Addresse (Range 0 to
31) als Index immer 8 Bits in dieser Speichermatrix abspeichern. Bei
auslesen aber müssen nun die Zeilen a 32 Bits an einem 32Bit breiten
Port des CPLD angelegt werden.

Mein bisheriger Source "codiert" das manuell und verbraucht über 500
Makrozellen, ist also unzumutbar.

Meine Frage ist also wie man in VHDL sowas programmieren muß. Im WEB
hatte ich schon gesucht und leider nichts gefunden.

Nachfolgend mal eine verkürzte Version.

Gruß Hagen



entity Test is
  port(
    -- Addresseingänge A0-A5
    A: in std_logic_vector(5 downto 0);
    -- Datenbus
    D: in std_logic_vector(7 downto 0);
    -- Clock, Chipselect, WR
    CLK,CS,WR: in std_logic;

    ROWS: out std_logic_vector(31 downto 0);
  );
end LED;


architecture behavioral of Test is

  signal M0: std_logic_vector(31 downto 0);
  signal M1: std_logic_vector(31 downto 0);
  signal M2: std_logic_vector(31 downto 0);
  signal M3: std_logic_vector(31 downto 0);
  signal M4: std_logic_vector(31 downto 0);
  signal M5: std_logic_vector(31 downto 0);
  signal M6: std_logic_vector(31 downto 0);
  signal M7: std_logic_vector(31 downto 0);

begin


  process(CLK, CS, WR, A, D)
  begin

    if CS = '1' and WR = '0' then
      if A(5) = '0' then

        case A(4 downto 0) is
          when "00000" =>
            M0(0) <= D(0);
            M1(0) <= D(1);
            M2(0) <= D(2);
            M3(0) <= D(3);
            M4(0) <= D(4);
            M5(0) <= D(5);
            M6(0) <= D(6);
            M7(0) <= D(7);
          when "00001" =>
            M0(1) <= D(0);
            M1(1) <= D(1);
            M2(1) <= D(2);
            M3(1) <= D(3);
            M4(1) <= D(4);
            M5(1) <= D(5);
            M6(1) <= D(6);
            M7(1) <= D(7);
          when "00010" =>
            M0(2) <= D(0);
            M1(2) <= D(1);
            M2(2) <= D(2);
            M3(2) <= D(3);
            M4(2) <= D(4);
            M5(2) <= D(5);
            M6(2) <= D(6);
            M7(2) <= D(7);
         usw. usw. bis "11111"
        end case;
      end if;
    end if;
  end process;

end behavioral;

Später wollte ich mit zB.

  ROWS <= M0;

die Bits umsortiert wieder ausgeben.

von Matthias (Gast)


Lesenswert?

Hi

allein für die Speicherung der 256 Bit wirst du 256 Makrozellen
brauchen. CPLDs und FPGAs sind, aufgrund ihres internen Aufbaus,
denkbar ungeeignet zur Speicherung von Daten da dafür ein FF
erforderlich ist und die sind sowohl in FPGAs als auch in CPLDs immer
knapp.

FPGAs habe deshalb z.T. Block-RAMs über den Chip verteilt. Das sind
spezielle Blöcke die nur Daten speichern können aber ansonsten nicht
zur Programierung geeignet sind (Evtl. noch als Look-Up Tabelle)

Matthias

von tobias hofer (Gast)


Lesenswert?

ich würde das mit einem ram lösen:


ram initialisieren:

type RAM_32_8 is array(31 downto 0) of std_logic(7 downto 0);
signal MEM: RAM_32_8;

schreiben:

WRITE_RAM: process(CS)
           if CS'event and CS = '1' then
              if Wr = '0' then
                MEM(adresse) <= daten;
              end if;
           end if;
           end process WRITE_RAM;

gruss tobias

von Hagen (Gast)


Lesenswert?

Danke, auf eine ähnliche syndaktische Lösung bin ich heute nacht auch
gekommen:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity test is
  port(
    A: in integer range 0 to 31;
    C: in integer range 0 to 7;
    D: in std_logic_vector(7 downto 0);
    CS,WR: std_logic;
    ROWS: buffer std_logic_vector(31 downto 0)
  );
end test;


architecture behavioral of test is

  type RAM is array(integer range 0 to 7) of std_logic_vector(31 downto
0);
  signal Pixel: RAM;

begin

  process(CS, WR, A, D, C)
  begin
    if CS = '1' and WR = '0' then
      Pixel(0)(A) <= D(0);
      Pixel(1)(A) <= D(1);
      Pixel(2)(A) <= D(2);
      Pixel(3)(A) <= D(3);
      Pixel(4)(A) <= D(4);
      Pixel(5)(A) <= D(5);
      Pixel(6)(A) <= D(6);
      Pixel(7)(A) <= D(7);
    else
      ROWS <= Pixel(C);
    end if;
  end process;


end behavioral;


es sind aber eben 256 FF's nötig, und beide Entwicklungsumgebungen
Quartus und Xilinx ISP können mit dem VHDL nichts anfangen. Quartus
bricht ab mit der Meldung das es kein entsprechende Device findet, das
mehr als 352 Makrozellen unterstützt. Xilinx ISP meint das diese Design
mindestens 577 Makrozellen benötigen würde.

Erst mit der Deklartion von,

  type RAM is array(integer range 0 to 7) of std_logic_vector(11 downto
0);
  signal Pixel: RAM;

also ein Bit Vector bei weitem zu klein für mich, reichen die
Makrozellen aus. Das ist das erste Problem -> mein Design ist zu
komplex weil es zu viele FF's benötigt und eben weil es die daten
"überkreuz" ein-/auslesen will was dazu führt das für jedes Bit ein
1-Bit Latch benötigt wird. Soweit glaube ich die Sache verstanden zu
haben, vielleicht irre ich mich ja !?

Das zweite Problem entsteht dann im fertigen VHDL, das diese daten
sozusagen als gemultiplexte PWM mit einem externen Takt an den
Ausgängen anlegen sollte. Der obige VHDL Source ist also nur eine
gestutzte Version die sich auf die "RAM" Zellen konzentriert. Wird
aber mit der getakteten Version gearbeitet wollen beide Programme
garnicht mehr compilieren.

Gruß Hagen

von Hagen (Gast)


Lesenswert?

Die Frage ist nun ob es denoch irgend ein Weg gibt das hinzubekommen.
Ich hatte schon daran gedacht einen Mini-SRAM von 512 Bits
anzuschließen, nur finde ich da nichts passendes.

Gruß Hagen

von Martin (Gast)


Lesenswert?

Hallo

Hast du schon eine Lösung für dieses Problem schon gefunden? Ich sitze
an einem ähnlichen Problem.

MFG Martin

von Hagen (Gast)


Lesenswert?

Ja, ich arbeite an einer externen SRAM Ansteuerung. Der CPLD wird dabei
mit 64 MHz getaktet. Teilt das runter mit 4 um für den AVR den 16MHz
Talt zuliefern. Der AVR liegt mit AD0-AD7,A8-A15, WR\, RD\, ALE am
CPLD an. Der externe SRAM, 128Kb, liegt ebenfalls mit IO0-IO7, A0-A16,
OE, WR\, CS am CPLD an. Der SRAM ist ein 10-15ns Typ. Soweit die
Hardware.

Der CPLD steuert nun den Zugriff auf den SRAM. Ein SRAM Zugriff
benötigt 1 kompletten CPLD Takt, also ca. 15ns. Der AVR greift
innerhalb von 3 MCU Takten über sein XMEM Interface auf den CPLD zu.
D.h. ein "LD Register, Addresse" benötigt 3 MCU Takte. Aber davon
wird nur 1 MCU Takt lang tatsächlich die WR\ oder RD\ Leitung
angesteuert. Der AVR benötigt also, asynchron zum Takt, minimal 63ns,
wovon aber nur 21ns tatsächlicher Schreib-/Lesezugriff darstellt. Der
Rest von 42ns wird für die ALE + Addresslatch benötigt. Der CPLD kann
aber mit 15ns zugreifen und teilt somit die 21ns des AVR's in zwei
teile auf. Insgesamt ergibt sich dadurch ein Ratio von 1 zu 5. D.h.
inder gleichen Zeit wo der AVR eine SRAM Adresse ausliest kann der CPLD
5mal Speicheradressendddressen auslesen oder schreiben. Im Worstcase
kann sich dies auf 2/3 reduzieren.

Im Grunde wird daraus dann ein "Dual Port SRAM" bei dem der AVR und
der CPLD gemultiplext in 50% der AVR Zugriffszeit auf den SRAM
zugreifen. Der CPLD packt also in 1 AVR-MCU Takt = 1 Takt WR\, RD\ ==
Low Pegel insgesammt 2 Speicherzugriffe rein. Einen für den AVR und
einen für den CPLD. Deshalb benötige ich 10-15ns SRAM, der aber leicht
zu beschaffen ist.

Für einen 32MHz CPLD Takt mit 1/3 Ratio habe ich schon ein VHDL fertig
unter Quartus II simuliert. Aber ganz gefällt mir dies noch nicht da
bei der Timing-Analyse einige Steuerleitungen nicht korrekt zu den
Daten- Addressleitungen interagieren. Deshalb binich auch auf 64MHz
CPLD höher gegangen.

Nun, Hintergrund der ganzen Sache ist ein "Display-Controller" zu
Ansteuerung von LEDs. Der CPLD und der AVR teilen sich einen SRAM der
in Teilen den Display-RAM enthält. Desweiteren muß der CPLD nun dieses
Display an die LEDs ausgeben. Dies erfordert ein Multiplexingund auch
Farbdekodierung der Pixelwerte um die RGB-LEDs anzusteuern.

Den Gedanken im CPLD selber die RAM Zellen zu integrieren habe ich
komplett verworfen.

Gruß Hagen

von Hagen (Gast)


Lesenswert?

Ach mann, ich bin da mit den Timings durcheinander gekommen.

1 MCU Takt ist bei 16 Mhz natürlich 62ns lang. Bei Zugriff über XMEM
auf erxterne Geräte fallen 3 Takte an. 2 Takte für den externen
Addresslatch und 1 Takt zum realen lesen oder schreiben ins SRAM. Somit
benötigt ein "LD register, Addresse" 186ns Zeit.

Der CPLD greift mit 30ns auf den SRAM zu,und kann so in 1 AVR MCU Takt
a 62ns zwei komplette SRAM Zugriffe reinpacken. Einer dieser Zugriff
befriedigt die Lese/Schreibanforderung des AVRs und der andere steht
dem CPLD zur Verfügung. Da der AVR aber 3 MCU Takte benötigt heist die
das im Normalfalle der CPLD 5 mal öffter als der AVR aus dem SRAM
lesen/schreiben kann.

Dieses Sharing muss man beim AVR benutzen weil laut Atmels
Datenblättern das XMEM Interface asynchron zum AVR Takt ist. D.h. durch
Temperatur-/Spanungsdrifts verändern sich die Slopes und es gibt laut
Atmel keine Möglichkeit über einen externen synchronen Takt
verschiedene externe Geräte mit dem AVR XMEM Interface zu
synchronisieren. In kurz: die Lese-/Screibanforderungen des AVR's an
den CPLD kann zum CPLD Takt asynchron erfolgen. Damit der CPLD wieder
"synchron" zur Anforderung des AVRs wird muß dessen Timing also 2 mal
größer als das des AVR's sein.

Gruß Hagen

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.