Forum: FPGA, VHDL & Co. Xilinx FPGA: Organisation des BlockRAM


von Martin K. (mkohler)


Lesenswert?

eine kurze Frage zu Xilinx BlockRAM im Spartan 3E:
Wie wird ein BlockRAM mit Speicherbreite 4Bit umgesetzt? Werden trotzdem 
8Bit verwendet, der Rest ist einfach nicht benutzt oder wird ein 
"echtes" 4Bit RAM erstellt?
Wäre auch ein 1Bit RAM möglich?

Sowas stelle ich mir vor:
1
entity RAM_4Bit_ is
2
  port (
3
    ADDR  : in  std_logic_vector(9 downto 0); -- Address
4
    DI    : in  std_logic_vector(3 downto 0); -- Data in
5
    DO    : out std_logic_vector(3 downto 0); -- Data out
6
    clk   : in std_logic;                     -- Clock
7
    WE    : in std_logic;                     -- Write Enable
8
    CE    : in std_logic                      -- Chip Enable
9
  );
10
end RAM_4Bit;
11
 
12
architecture RAM_4Bit_arch of RAM_4Bit is
13
  type ram_type is array (9 downto 0)
14
                   of std_logic_vector (3 downto 0);
15
  signal RAM : ram_type := (others => "0000");
16
begin
17
  process (clk)
18
  begin
19
    if (rising_edge(clk)) then
20
      if (CE = '1') then
21
        if (WE = '1') then
22
          RAM(to_integer(ADDR)) <= DI;
23
        end if;
24
        DO <= RAM(to_integer(ADDR));
25
      end if;
26
    end if;
27
  end process;
28
end RAM_4Bit_arch;

Danke für die Antworten.
Gruss, Martin Kohler

von Duke Scarring (Gast)


Lesenswert?

Dann klick doch mal auf Synthesize und gucke, was rauskommt:
1
Loading device for application Rf_Device from file '4vlx15.nph' in environment ...
2
INFO:Xst:2452 - Unit <RAM_4Bit> : The small RAM <Mram_RAM> will be implemented on LUTs in order to maximize performance and save block RAM resources. If you want to force its implementation on block, use option/constraint ram_style.
3
    -----------------------------------------------------------------------
4
    | ram_type           | Distributed                         |          |
5
    -----------------------------------------------------------------------
6
    | Port A                                                              |
7
    |     aspect ratio   | 10-word x 4-bit                     |          |
8
    |     clkA           | connected to signal <clk>           | rise     |
9
    |     weA            | connected to signal <WE_0>          | high     |
10
    |     addrA          | connected to signal <ADDR>          |          |
11
    |     diA            | connected to signal <DI>            |          |
12
    |     doA            | connected to internal node          |          |
13
    -----------------------------------------------------------------------

Das Ergebnis ist (teilweise) vom Device abhängig.

Duke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> wird ein "echtes" 4Bit RAM erstellt?
Ja.
Allerdings werden bei deinem BRAM je nach FPGA einige Bits nicht 
verwendet. Du brauchst nur 4096 Bits, ein BRAM eines S3 hat 18kBit, d.h. 
du verwendest nur 1/4 davon (die unbenutzen Adressen werden einfach auf 
0 gelegt).

> Wäre auch ein 1Bit RAM möglich?
Ja. Steht in der XAPP463.

von Martin K. (mkohler)


Lesenswert?

Danke euch beiden für die Antworten.
Ich werde mal die AppNote studieren.
(ich wusste, dass sicher eine zum Thema bestehen muss, habe sie aber 
nicht gefunden)

Martin

von Duke Scarring (Gast)


Lesenswert?

Dein Speicher enthält übrigens nur 10 Elemente:
1
type ram_type is array (9 downto 0) ...

Wolltest Du das?

Oder doch eher so?!:
1
type ram_type is array (0 to 2**ADDR'length-1) ...

Duke

von Martin K. (mkohler)


Lesenswert?

Duke Scarring wrote:
> Dein Speicher enthält übrigens nur 10 Elemente:
> Oder doch eher so?!:
>
1
> type ram_type is array (0 to 2**ADDR'length-1) ...
2
>
Du hast recht, natürlich!

von Martin K. (mkohler)


Lesenswert?

Anschlussfrage:
Ist es auch möglich, ein RAM zu erstellen, welches auf der einen Seite 
2^9x32Bit organisiert ist, auf der anderen Seite 2^14*1Bit ?

Meine bisherigen Abklärungen deuten auf ein "Nein" hin.

Der Workaround wäre dann wohl: auch auf der zweiten Seite mit einer 
grösseren Datenbreite zugreifen und die Bits mit nachgeschalteter Logik 
decodieren.

Martin

von Christian R. (supachris)


Angehängte Dateien:

Lesenswert?

Zumindest kann man es im Core Generator bei Xilinx einstellen. Sollte 
also klappen.

von Morin (Gast)


Lesenswert?

> Anschlussfrage:
> Ist es auch möglich, ein RAM zu erstellen, welches auf der einen Seite
> 2^9x32Bit organisiert ist, auf der anderen Seite 2^14*1Bit ?

Ja. Ich habe selbst schon mit einem RAM gearbeitet, welches auf der 
einen Seite als 2k*16 Bits und auf der anderen Seite als 1k*32 Bits 
organisiert war. Bis auf die konkreten Zahlen habe ich also "genau das" 
schon gemacht.

von Morin (Gast)


Lesenswert?

Nachtrag: Dieser RAM wurde problemlos auf 2 BlockRAMs abgebildet (die 
Zahl 2 hier wegen der Gesamtgröße 4kB, nicht wegen der zwei 
Zugriffsmodi).

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Das geht aber glaub ich nur wenn die eine Seite eine ganzzahlige 
Vielfache einer zweierpotenz ist und hängt ggf auch vom Chip ab, ich 
würd einfach mal schauen was der Coregenerator sagt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> 2^9x32Bit organisiert ist, auf der anderen Seite 2^14*1Bit ?
> Meine bisherigen Abklärungen deuten auf ein "Nein" hin.
Ich meine die XAPP463 auch so interpretieren zu können :-/

> Der Workaround wäre dann wohl: auch auf der zweiten Seite mit einer
> grösseren Datenbreite zugreifen
Das Problem ist nicht die Seite mit 1 Bit. Es geht um die Breitseite :-o
Es gibt kein RAMB16_S1_S32, mit dem ein direktes Ummappen möglich wäre.
Es gibt nur einen RAMB16_S1_S36, also 1 Bit auf der einen, 36 bit auf 
der anderen Seite :-/
Wenn ich z.B. auf der 1-Bit Seite an Adresse 0 etwas schreibe, kommt das 
an der breiten Seite an Adresse 0 Bit 0 heraus.
Wenn ich auf auf der 1-Bit Seite an Adresse 31 etwas schreibe, kommt das 
an der breiten Seite auf Adresse 0 Bit 31 heraus.
Wenn ich jetzt aber auf auf der 1-Bit Seite an Adresse 32 etwas 
schreibe, und bei einem 32-Bit Wort dann die Adresse 1 Bit 0 erwarten 
würde, kommt das am BRAM an der breiten Seite auf Adresse 0 Bit 32 
heraus.

D.h. das BRAM kann nicht einfach als 1-->32 Bit-Buskonverter verwendet 
werden. Eine Möglichkeit wäre jetzt, beim Schreiben auf der 1-Bit-Seite 
die Adresse so zu manipulieren, dass auf der 36-Bit-Seite die Bits 
35..32 nicht beschrieben werden.

von Gast (Gast)


Lesenswert?

Geht doch:

RAMB16_S1_S36 ist genau das, was Du brauchst:
an den Bits 0..31 (DOA(31 downto 0) oder DOB(31 downto 0))
liegen genau die 32 'eingeschriebenen' Bits

Bits 32..35 (DOPA(3 downto 0) oder DOPB(3 downto 0) einfach
'open' lassen

von Martin K. (mkohler)


Lesenswert?

Gast wrote:
> RAMB16_S1_S36 ist genau das, was Du brauchst:

Sieht gut aus.
Wie verwende ich dieses Konstrukt nun konkret in meinem VHDL Code?
Kann mir da jemand evtl. ein Beispiel zeigen?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Wie verwende ich dieses Konstrukt nun konkret in meinem VHDL Code?
Das sieht gut aus:
http://www.te.rl.ac.uk/esdg/cms-fed/xilinx-fpgas/virtex2/templates/vhdl/blockram/vhdl/SelectRAM_A1_B36.vhd

von Martin K. (mkohler)


Angehängte Dateien:

Lesenswert?

Lothar Miller wrote:
> Das sieht gut aus:
Tut es, ja.

Ich binde also das Dual Port RAM also als "component" ein:
1
component RAMB16_S1_S36 
2
  port (
3
  DIA     : in std_logic_vector (0 downto 0);
4
  ADDRA   : in std_logic_vector (13 downto 0);
5
  ENA     : in std_logic;
6
  WEA     : in std_logic;
7
  SSRA    : in std_logic;
8
  CLKA    : in std_logic;
9
  DOA     : out std_logic_vector (0 downto 0);
10
11
  DIB     : in std_logic_vector (31 downto 0);
12
  DIPB    : in std_logic_vector (3 downto 0);
13
  ADDRB   : in std_logic_vector (8 downto 0);
14
  ENB     : in std_logic;
15
  WEB     : in std_logic;
16
  SSRB    : in std_logic;
17
  CLKB    : in std_logic;
18
  DOB     : out std_logic_vector (31 downto 0);
19
  DOPB    : out std_logic_vector (3 downto 0)  
20
  ); 
21
end component;

und verwende das Teil in der üblichen Art als Instanz:
1
U_RAMB16_S1_S36: RAMB16_S1_S36
2
  port map (
3
  DIA     => X, -- insert 1 bit data in bus (<0 downto 0>)
4
  ADDRA   => Y, -- insert 14 bits address bus
5
  ENA     => Z, -- insert enable signal
6
  ...

Soweit, so gut.
Welche RAM Konfigurationen möglich sind, entnehme ich der AppNote 463, 
Seite 10, Tabelle 7 (Bild im Anhang)

Woher nehme ich nun aber die Port Beschreibung? Muss ich mir diese aus 
einem Beispiel kopieren oder sind die Port Maps für die einzelnen 
Konfigurationsvarianten irgendwo abrufbar?
Aus dem Datenblatt zusammenklauben erscheint mir etwas mühsam...

Danke für die bisherigen Antworten.

von Gast (Gast)


Lesenswert?

<Xilinx-Installation>\doc\usenglish\books\docs\<MeinTyp>\<MeinTyp>.pdf

von Gast (Gast)


Lesenswert?

sorry - genauer

<Xilinx-Installation>\doc\usenglish\books\docs\<device>_hdl\<device>.pdf

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Martin Kohler wrote:
> Woher nehme ich nun aber die Port Beschreibung?
Die steht in den Komentaren hinter dem Beispiel. Da solltest du 
natürlich nicht X,Y und Z abschliessen, sondern eher z.B.
1
  port map (
2
  DIA     => datain,  -- insert 1 bit data in bus (<0 downto 0>)
3
  ADDRA   => addrin,  -- insert 14 bits address bus
4
  ENA     => '1',     -- insert enable signal / immer enabled
5
  WEA     => write,   -- insert write enable signal 
6
  SSRA    => '0',     -- insert set/reset signal
7
  CLKA    => clkin,   -- insert clock signal
8
  DOA     => open,    -- insert 1 bit data out bus (<0 downto 0>)
9
--
10
  DIB     => (others=>'0'), -- insert 32 bits data in bus (<31 downto 0>)
11
  DIPB    => (others=>'0'), -- insert 4 bits parity data in bus (or <35 downto 32>)
12
  ADDRB   => addrout, -- insert 9 bits address bus
13
  ENB     => '1',     -- insert enable signal / immer enabled
14
  WEB     => '0',     -- insert write enable signal / nur lesen
15
  SSRB    => '0',     -- insert set/reset signal
16
  CLKB    => clkout,  -- insert clock signal
17
  DOB     => dataout, -- insert 32 bits data out bus (<31 downto 0>)
18
  DOPB    => open     -- insert 4 bits parity data out bus (or <35 downto 32>)
19
  );
Hier jetzt 1 Bit Eingangsbreite und 32 Bit Ausgangsbreite. Du könntest 
natürlich auch auf beiden Seiten lesen bzw. schreiben.

von Martin K. (mkohler)


Lesenswert?

Danke für die bisherigen Antworten!

Lothar Miller wrote:
> Die steht in den Komentaren hinter dem Beispiel. Da solltest du
> natürlich nicht X,Y und Z abschliessen, sondern eher z.B.
Ist schon klar, danke trotzdem ;-)

Gast wrote:
> sorry - genauer
> <Xilinx-Installation>\doc\usenglish\books\docs\<device>_hdl\<device>.pdf
bei mir:
C:\Programme\Xilinx_92i\doc\usenglish\books\docs\s3edl
--> also eher: ...\docs\<device>dl

Die Port Beschreibungen habe ich nun im ISE auch gefunden:
>ISE x.y >Edit >Language Templates >VHDL >Device Primitive Instantiation >FPGA 
>RAM/ROM >Block RAM >...Spartan-3E >Dual-Port (Mis-matched Port Widths) >16k/1k x 
1/16 ...

Wenn ich nun den oben beschriebenen Typ wähle erhalte ich den folgenden 
(hier abgekürzten) Code:
1
--  <-----Cut code below this line and paste into the architecture body---->
2
   -- RAMB16_S1_S18: Virtex-II/II-Pro, Spartan-3/3E 16k/1k x 1/16 + 0/2 Parity bits Dual-Port RAM
3
   -- Xilinx HDL Language Template, version 9.2.1i
4
   RAMB16_S1_S18_inst : RAMB16_S1_S18
5
   generic map (
6
      INIT_A => "0", --  Value of output RAM registers on Port A at startup
7
      INIT_B => X"00000", --  Value of output RAM registers on Port B at startup
8
      SRVAL_A => "0", --  Port A ouput value upon SSR assertion
9
      SRVAL_B => X"00000", --  Port B ouput value upon SSR assertion
10
      WRITE_MODE_A => "WRITE_FIRST", --  WRITE_FIRST, READ_FIRST or NO_CHANGE
11
      WRITE_MODE_B => "WRITE_FIRST", --  WRITE_FIRST, READ_FIRST or NO_CHANGE
12
      SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" 
13
      -- The following INIT_xx declarations specify the initial contents of the RAM
14
      -- Port A Address 0 to 4095, Port B Address 0 to 255
15
      INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000",
16
      ...
17
      INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000",
18
      -- Port A Address 4096 to 8191, Port B Address 256 to 511
19
      INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000",
20
      ...
21
      INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000",
22
      -- Port A Address 8192 to 12287, Port B Address 512 to 767
23
      INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000",
24
      ...
25
      INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000",
26
      -- Port A Address 12288 to 16383, Port B Address 768 to 1023
27
      INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000",
28
      ...
29
      INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000",
30
      -- The next set of INITP_xx are for the parity bits
31
      -- Port B Address 0 to 255
32
      INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000",
33
      ...
34
      INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000")
35
   port map (
36
      DOA => DOA,       -- Port A 1-bit Data Output
37
      DOB => DOB,       -- Port B 16-bit Data Output
38
      DOPB => DOPB,     -- Port B 2-bit Parity Output
39
      ADDRA => ADDRA,   -- Port A 14-bit Address Input
40
      ADDRB => ADDRB,   -- Port B 10-bit Address Input
41
      CLKA => CLKA,     -- Port A Clock
42
      CLKB => CLKB,     -- Port B Clock
43
      DIA => DIA,       -- Port A 1-bit Data Input
44
      DIB => DIB,       -- Port B 16-bit Data Input
45
      DIPB => DIPB,     -- Port-B 2-bit parity Input
46
      ENA => ENA,       -- Port A RAM Enable Input
47
      ENB => ENB,       -- PortB RAM Enable Input
48
      SSRA => SSRA,     -- Port A Synchronous Set/Reset Input
49
      SSRB => SSRB,     -- Port B Synchronous Set/Reset Input
50
      WEA => WEA,       -- Port A Write Enable Input
51
      WEB => WEB        -- Port B Write Enable Input
52
   );
53
   -- End of RAMB16_S1_S18_inst instantiation

Die im Teil "generic map" eingetragenen Daten werden als Initialwert in 
s DPRAM übernommen, ich könnte so z.B. den Programmcode für einen 
PicoBlaze einfügen, richtig?

Sehe ich auch richtig, dass ich den "generig map" Teil weglassen kann 
und dann alles mit '0' resp. (others => '0') initialisiert wird?

Gruss, Martin

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.