Datum: 23.04.2009 10:57
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:
entity RAM_4Bit_ is port ( ADDR : in std_logic_vector(9 downto 0); -- Address DI : in std_logic_vector(3 downto 0); -- Data in DO : out std_logic_vector(3 downto 0); -- Data out clk : in std_logic; -- Clock WE : in std_logic; -- Write Enable CE : in std_logic -- Chip Enable ); end RAM_4Bit; architecture RAM_4Bit_arch of RAM_4Bit is type ram_type is array (9 downto 0) of std_logic_vector (3 downto 0); signal RAM : ram_type := (others => "0000"); begin process (clk) begin if (rising_edge(clk)) then if (CE = '1') then if (WE = '1') then RAM(to_integer(ADDR)) <= DI; end if; DO <= RAM(to_integer(ADDR)); end if; end if; end process; end RAM_4Bit_arch; |
Danke für die Antworten. Gruss, Martin Kohler
Datum: 23.04.2009 11:13
Dann klick doch mal auf Synthesize und gucke, was rauskommt:
Loading device for application Rf_Device from file '4vlx15.nph' in environment ...
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.
-----------------------------------------------------------------------
| ram_type | Distributed | |
-----------------------------------------------------------------------
| Port A |
| aspect ratio | 10-word x 4-bit | |
| clkA | connected to signal <clk> | rise |
| weA | connected to signal <WE_0> | high |
| addrA | connected to signal <ADDR> | |
| diA | connected to signal <DI> | |
| doA | connected to internal node | |
-----------------------------------------------------------------------
|
Das Ergebnis ist (teilweise) vom Device abhängig. Duke
Datum: 23.04.2009 11:36
> 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.
Datum: 23.04.2009 12:53
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
Datum: 23.04.2009 15:10
Dein Speicher enthält übrigens nur 10 Elemente:
type ram_type is array (9 downto 0) ... |
Wolltest Du das? Oder doch eher so?!:
type ram_type is array (0 to 2**ADDR'length-1) ... |
Duke
Datum: 23.04.2009 15:40
Duke Scarring wrote: > Dein Speicher enthält übrigens nur 10 Elemente: > Oder doch eher so?!: >
> type ram_type is array (0 to 2**ADDR'length-1) ... > |
Du hast recht, natürlich!
Datum: 23.04.2009 15:44
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
Datum: 23.04.2009 16:07
Angehängte Dateien:Zumindest kann man es im Core Generator bei Xilinx einstellen. Sollte also klappen.
Datum: 23.04.2009 16:53
> 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.
Datum: 23.04.2009 16:55
Nachtrag: Dieser RAM wurde problemlos auf 2 BlockRAMs abgebildet (die Zahl 2 hier wegen der Gesamtgröße 4kB, nicht wegen der zwei Zugriffsmodi).
Datum: 24.04.2009 11:17
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.
Datum: 24.04.2009 11:59
> 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.
Datum: 24.04.2009 18:08
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
Datum: 27.04.2009 10:47
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?
Datum: 27.04.2009 13:52
> 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/v...
Datum: 27.04.2009 14:46
Angehängte Dateien:Lothar Miller wrote:
> Das sieht gut aus:
Tut es, ja.
Ich binde also das Dual Port RAM also als "component" ein:component RAMB16_S1_S36 port ( DIA : in std_logic_vector (0 downto 0); ADDRA : in std_logic_vector (13 downto 0); ENA : in std_logic; WEA : in std_logic; SSRA : in std_logic; CLKA : in std_logic; DOA : out std_logic_vector (0 downto 0); DIB : in std_logic_vector (31 downto 0); DIPB : in std_logic_vector (3 downto 0); ADDRB : in std_logic_vector (8 downto 0); ENB : in std_logic; WEB : in std_logic; SSRB : in std_logic; CLKB : in std_logic; DOB : out std_logic_vector (31 downto 0); DOPB : out std_logic_vector (3 downto 0) ); end component; |
und verwende das Teil in der üblichen Art als Instanz:
U_RAMB16_S1_S36: RAMB16_S1_S36 port map ( DIA => X, -- insert 1 bit data in bus (<0 downto 0>) ADDRA => Y, -- insert 14 bits address bus ENA => Z, -- insert enable signal ... |
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.
Datum: 27.04.2009 16:37
<Xilinx-Installation>\doc\usenglish\books\docs\<MeinTyp>\<MeinTyp>.pdf
Datum: 27.04.2009 16:38
sorry - genauer <Xilinx-Installation>\doc\usenglish\books\docs\<device>_hdl\<device>.pdf
Datum: 27.04.2009 19:13
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.port map ( DIA => datain, -- insert 1 bit data in bus (<0 downto 0>) ADDRA => addrin, -- insert 14 bits address bus ENA => '1', -- insert enable signal / immer enabled WEA => write, -- insert write enable signal SSRA => '0', -- insert set/reset signal CLKA => clkin, -- insert clock signal DOA => open, -- insert 1 bit data out bus (<0 downto 0>) -- DIB => (others=>'0'), -- insert 32 bits data in bus (<31 downto 0>) DIPB => (others=>'0'), -- insert 4 bits parity data in bus (or <35 downto 32>) ADDRB => addrout, -- insert 9 bits address bus ENB => '1', -- insert enable signal / immer enabled WEB => '0', -- insert write enable signal / nur lesen SSRB => '0', -- insert set/reset signal CLKB => clkout, -- insert clock signal DOB => dataout, -- insert 32 bits data out bus (<31 downto 0>) DOPB => open -- insert 4 bits parity data out bus (or <35 downto 32>) ); |
Hier jetzt 1 Bit Eingangsbreite und 32 Bit Ausgangsbreite. Du könntest natürlich auch auf beiden Seiten lesen bzw. schreiben.
Datum: 28.04.2009 08:20
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:
-- <-----Cut code below this line and paste into the architecture body----> -- RAMB16_S1_S18: Virtex-II/II-Pro, Spartan-3/3E 16k/1k x 1/16 + 0/2 Parity bits Dual-Port RAM -- Xilinx HDL Language Template, version 9.2.1i RAMB16_S1_S18_inst : RAMB16_S1_S18 generic map ( INIT_A => "0", -- Value of output RAM registers on Port A at startup INIT_B => X"00000", -- Value of output RAM registers on Port B at startup SRVAL_A => "0", -- Port A ouput value upon SSR assertion SRVAL_B => X"00000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Port A Address 0 to 4095, Port B Address 0 to 255 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", ... INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Port A Address 4096 to 8191, Port B Address 256 to 511 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", ... INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Port A Address 8192 to 12287, Port B Address 512 to 767 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", ... INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Port A Address 12288 to 16383, Port B Address 768 to 1023 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", ... INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Port B Address 0 to 255 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", ... INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => DOA, -- Port A 1-bit Data Output DOB => DOB, -- Port B 16-bit Data Output DOPB => DOPB, -- Port B 2-bit Parity Output ADDRA => ADDRA, -- Port A 14-bit Address Input ADDRB => ADDRB, -- Port B 10-bit Address Input CLKA => CLKA, -- Port A Clock CLKB => CLKB, -- Port B Clock DIA => DIA, -- Port A 1-bit Data Input DIB => DIB, -- Port B 16-bit Data Input DIPB => DIPB, -- Port-B 2-bit parity Input ENA => ENA, -- Port A RAM Enable Input ENB => ENB, -- PortB RAM Enable Input SSRA => SSRA, -- Port A Synchronous Set/Reset Input SSRB => SSRB, -- Port B Synchronous Set/Reset Input WEA => WEA, -- Port A Write Enable Input WEB => WEB -- Port B Write Enable Input ); -- 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

