Forum: FPGA, VHDL & Co. Sinus LUT in BlockRAM


von Marcel D. (diablokiller999)


Lesenswert?

Hi Leutz!
Ich habe mir eine Lookup Table für eine DDS geschrieben, diese 
beinhaltet einen Sinus in 20Bit Breite. Leider schmeißt mir mein Fitter 
das Teil nicht in den BlockRAM, sondern nutzt Logikeinheiten dafür. Mich 
wundert das verhalten, weil bei einem getakteten Zugriff doch eigentlich 
der BlockRAM genutzt werden sollte? Eventuell sieht ja einer den Fehler 
:)
Das ganze wird auf einen MAX10 gepackt...
1
library ieee;
2
use ieee.std_logic_1164.ALL;
3
use ieee.numeric_std.ALL;
4
use ieee.math_real.all;
5
6
entity DDS_LUT is
7
8
    generic (
9
        OUTPUT_WIDTH:   integer := 32;
10
        ADDRESS_WIDTH:  integer := 12
11
    );
12
  port 
13
  (
14
    clk    : in std_logic;
15
    raddr  : in std_logic_vector(ADDRESS_WIDTH-1 downto 0);
16
    q    : out std_logic_vector(OUTPUT_WIDTH-1 downto 0)
17
  );
18
19
end DDS_LUT;
20
21
architecture rtl of DDS_LUT is
22
23
  -- Build a 2-D array type for the RAM
24
  subtype word_t is std_logic_vector(OUTPUT_WIDTH-1 downto 0);
25
  type memory_t is array((2**ADDRESS_WIDTH)-1 downto 0) of word_t;
26
    constant MEM_SIZE : integer := 2**ADDRESS_WIDTH;
27
    
28
function init_ram
29
    return memory_t is 
30
    constant SCALE : real := 2**(real(OUTPUT_WIDTH-1));
31
    constant STEP  : real := 1.0/real(MEM_SIZE);
32
  variable tmp : memory_t := (others => (others => '0'));
33
    begin 
34
        for i in 0 to MEM_SIZE-1 loop
35
            tmp(i) := std_logic_vector(to_signed(integer(sin(2.0*MATH_PI*real(i)*STEP)*(SCALE-real(0.5))+SCALE-real(0.5)),OUTPUT_WIDTH));
36
        end loop;    
37
    return tmp;
38
end init_ram;   
39
    
40
  -- Declare the RAM signal.  
41
  signal ram : memory_t := init_ram;
42
43
    
44
    begin
45
46
  process(clk)
47
  begin
48
  if(rising_edge(clk)) then 
49
    q <= ram(to_integer(unsigned(raddr)));
50
  end if;
51
  end process;
52
53
end rtl;

: Bearbeitet durch User
von Martin O. (ossi-2)


Lesenswert?

Ich hatte neulich das gleiche Problem. Bei mir war die Löäsung die 
folgende:


Irgendwie hatte Quartus nicht genau mitbekommen, welches MAX10 Device
ich verwende. Daraufhin ging Quartus davon aus, dass ich ein "Compact"
Device habe. Diese können bei der Configuration keine ROM
Initialisierung. Draufhin hat Quartus konsequenterweise darauf
verzichtet, ROM-Tabellen zu verwenden.

Jetzt hab ich den Device-Typ offensichtlich richtig eingesstellt und
alle Methoden funktionieren jetzt vollautomatisch mit ROM und
Initialisierung.


Frage: Arbeitest Du zufällig mit dem MAX1000 Board?

: Bearbeitet durch User
von Duke Scarring (Gast)


Lesenswert?

Ich würde aus der Funktion eine impure-Funktion machen:
1
impure function init_ram return memory_t ...

Marcel D. schrieb:
> 20Bit Breite. Leider schmeißt mir mein Fitter
> das Teil nicht in den BlockRAM
Wie groß sind denn die BlockRAMs in Deinem MAX10? Bei Xilinx sind die 
üblicherweise 18 (oder 36) Bit breit, da wäre dann 20 Bit eher 
suboptimal.

Duke

von Marcel D. (diablokiller999)


Lesenswert?

Duke Scarring schrieb:
> Wie groß sind denn die BlockRAMs in Deinem MAX10? Bei Xilinx sind die
> üblicherweise 18 (oder 36) Bit breit, da wäre dann 20 Bit eher
> suboptimal.

Laut Datenblatt kann der BRAM wohl nur bestimmte Größen und meine 20Bit 
gehören nicht dazu. Werde wohl meine LUT auf 18 Bit runter schrauben 
müssen um in den Genuss von BRAM zu kommen, aber ich nutze einen 20 Bit 
DAC...

BTW, wo liegt der Unterschied zwischen pure und impure functions?

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Marcel D. schrieb:
> Laut Datenblatt kann der BRAM wohl nur bestimmte Größen und meine 20Bit
> gehören nicht dazu. Werde wohl meine LUT auf 18 Bit runter schrauben
> müssen um in den Genuss von BRAM zu kommen, aber ich nutze einen 20 Bit
> DAC...

wer hält dich davon ab, (z.B.) zwei jeweils 10 bit breite RAMs zu 
erzeugen?

von Marcel D. (diablokiller999)


Lesenswert?

Markus F. schrieb:
> wer hält dich davon ab, (z.B.) zwei jeweils 10 bit breite RAMs zu
> erzeugen?
Eigentlich sollte das der Synthetisierer/Fitter für mich machen oder 
nicht?
Habe meine Implementierung mit dem Template im Quartus verglichen, 
eigentlich sind sie identisch was das Auslesen der Werte angeht.

von Duke Scarring (Gast)


Lesenswert?

Marcel D. schrieb:
> BTW, wo liegt der Unterschied zwischen pure und impure functions?
1
The value returned by an impure function can depend on items other than just its input parameters (e.g.shared variables).
Ich weiß nicht, ob das wirklich relevant ist.

Marcel D. schrieb:
> Eigentlich sollte das der Synthetisierer/Fitter für mich machen oder
> nicht?
Ja, eigentlich schon, aber bei manchen Dingen muß man nachhelfen.

Marcel D. schrieb:
> ich nutze einen 20 Bit DAC...
Du könntest die zwei Bits durch Interpolation ermitteln. Oder erstmal 
auf "00" setzen.

Duke

von Marcel D. (diablokiller999)


Lesenswert?

Duke Scarring schrieb:
> Marcel D. schrieb:
>> ich nutze einen 20 Bit DAC...
> Du könntest die zwei Bits durch Interpolation ermitteln. Oder erstmal
> auf "00" setzen.

Habe die LUT auf 18 Bit verkleinert und die oberen Bits auf GND gesetzt, 
dennoch schmeißt er mir alles in Logikeinheiten :-/
Liegt das eventuell an den math-funktionen?

von Martin O. (ossi-2)


Lesenswert?

Hast Du geprüft (siehe mein obiger Post), dass das eingestellte Device 
nicht vom "Compact" Typ ist ?

von Markus F. (mfro)


Lesenswert?

Quartus scheint ein wenig pingelig, was den MAX10 angeht.

Ich habe das gerade mal ausprobiert: intern scheint Quartus aus deiner 
Initialisierungsfunktion eine .mif-Datei zu erzeugen und mit der den 
Speicher initialisieren zu wollen (jedenfalls liegt im .db-Verzeichnis 
eine). Bei der Synthese kam bei mir allerdings anschliessend tatsächlich 
auch erst die Fehlermeldung ".mif files are not supported on this 
device" und das ROM wurde final ein Gattergrab.

Es tut aber alles so wie gedacht, wenn in "Device->Device and Pin 
Options...->Internal Configuration" "Single Uncompressed Image with 
Memory Initialization ..." eingestellt ist. Das funktioniert natürlich 
nur bei den Käfern, die das auch unterstützen (offensichtlich nicht alle 
MAX10).

von chris (Gast)


Lesenswert?

Wäre für eine Sinus-Tabelle ROM nicht besser als RAM?

von Markus F. (mfro)


Lesenswert?

chris schrieb:
> Wäre für eine Sinus-Tabelle ROM nicht besser als RAM?

Das "echte" MAX10 ROM steht - zumindest soweit ich weiss - nur als 
Avalon memory mapped interface IP zur Verfügung. Das ist von VHDL-Seite 
aus halt nicht ganz so einfach zu greifen wie Block RAM.

von Mampf unterwegs (Gast)


Lesenswert?

chris schrieb:
> Wäre für eine Sinus-Tabelle ROM nicht besser als RAM?

Ganz klare Antwort: it depends ... :)

von Edi M. (Gast)


Lesenswert?

Entscheidende Frage: (für mich): Ist die so erzeugte Struktur kleiner, 
als das Ram?

von Gerhard H. (ghf)


Lesenswert?

Marcel D. schrieb:
> Duke Scarring schrieb:
>> Wie groß sind denn die BlockRAMs in Deinem MAX10? Bei Xilinx sind die
>> üblicherweise 18 (oder 36) Bit breit, da wäre dann 20 Bit eher
>> suboptimal.
>
> Laut Datenblatt kann der BRAM wohl nur bestimmte Größen und meine 20Bit
> gehören nicht dazu. Werde wohl meine LUT auf 18 Bit runter schrauben
> müssen um in den Genuss von BRAM zu kommen, aber ich nutze einen 20 Bit
> DAC...

Denke daran, du musst das Vorzeichenbit zu Füllen benutzen
und nicht einfach nur Nullen, sonst gibt's einen Fehler von
fast einem LSB.

>
> BTW, wo liegt der Unterschied zwischen pure und impure functions?

pure functions benutzen nur Angaben aus der Parameterliste
zu Errechnung des Resultats. Die Resultate sind überall und
jedesmal exakt gleich, ganz egal was sich in der Umgebung abspielt.

impure functions können auch globale inputs benutzen, z.B.
das Datum oder eine Eingabezeile. Ich glaube, das gilt auch
für outputs, die am Rückgabewert vorbei Information nach aussen mogeln,
im Stil wie writeline() oder so. Ich musste jedenfalls schon functions
als impure deklarieren, nur wegen Testausgaben.
VHDL nervt manchmal ganz grauslig.

---

Wenn Du das RAM als constant statt als variable deklarierst,
hilft das? Sind diese Blockrams mit einer Pipelinestufe zufrieden?

----

Es würde mich übrigens interessieren, ob meine Tabelle
aus dem anderen thread auch mit Quartus funktioniert.
Ich hätte Lust, die Pferde zu wechseln.

Gruß, Gerhard

von Gerhard H. (ghf)


Lesenswert?

Edi M. schrieb:
> Entscheidende Frage: (für mich): Ist die so erzeugte Struktur kleiner,
> als das Ram?

Wenn man freie RAMs hat, ist die Lösung aus Gattern grundsätzlich 
größer.
Und sie besteht aus lauter Funktionen mit sehr vielen Eingängen,
so dass typisch mehrere kombinatorische Gatter in Serie gebraucht
werden. Das schlägt sich natürlich auf die Geschwindigkeit.

Bei der Lösung auf opencores kannst du einfach die Zahl der
Pipelinestufen auf 0 setzen und den großen Topf Gattersuppe
begutachten, der vom Synthesizer dann erzeugt wird.
Da wird "sea of gates" ganz erschreckend real.

Gruß, Gerhard

von Marcel D. (diablokiller999)


Lesenswert?

Ich denke die Idee mit den Device Settings war die Richtige, nun ist 
laut Synthese recht viel im RAM und meine LEs nur zu 19% belegt, statt 
54% wie zuvor. Jedoch bekomme ich nun eine Fehlermeldung
1
Error (23035): Tcl error: Authorized application C:\INTELF~2\17.0\quartus\bin64\jtagserver.exe is enabled in the firewall.
2
]2;Altera Nios II EDS 17.0 [gcc4]Info: *******************************************************************
3
Info: Running Quartus Prime Convert_programming_file
4
    Info: Version 17.0.0 Build 595 04/25/2017 SJ Lite Edition
5
    Info: Copyright (C) 2017  Intel Corporation. All rights reserved.
6
    Info: Your use of Intel Corporation's design tools, logic functions 
7
    Info: and other software and tools, and its AMPP partner logic 
8
    Info: functions, and any output files from any of the foregoing 
9
    Info: (including device programming or simulation files), and any 
10
    Info: associated documentation or information are expressly subject 
11
    Info: to the terms and conditions of the Intel Program License 
12
    Info: Subscription Agreement, the Intel Quartus Prime License Agreement,
13
    Info: the Intel MegaCore Function License Agreement, or other 
14
    Info: applicable license agreement, including, without limitation, 
15
    Info: that your use is for the sole purpose of programming logic 
16
    Info: devices manufactured by Intel and sold by Intel or its 
17
    Info: authorized distributors.  Please refer to the applicable 
18
    Info: agreement for further details.
19
    Info: Processing started: Thu Oct 12 07:34:23 2017
20
Info: Command: quartus_cpf -c MCS2MAX10.cof
21
The compiled configuration mode Single Internal Compressed Image with ERAM does not support multiple pages
22
Error: Quartus Prime Convert_programming_file was unsuccessful. 0 errors, 0 warnings
23
    Error: Peak virtual memory: 314 megabytes
24
    Error: Processing ended: Thu Oct 12 07:34:24 2017
25
    Error: Elapsed time: 00:00:01
26
    Error: Total CPU time (on all processors): 00:00:01
27
cp: cannot stat 'files/mcs2max10_cfm1_auto.rpd': No such file or directory
28
cp: cannot stat 'files/MCS2MAX10.map': No such file or directory
29
cp: cannot stat 'files/MCS2MAX10.pof': No such file or directory
30
    while executing

: Bearbeitet durch User
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.