Alternative Zählerbeschreibung

Gast #2467493
Lesenswert?

Hallo,

ich habe folgenden Zähler:

1
process(clk)
2
begin
3
   if rising_edge(clk) then
4
         if cnt < cMAX then
5
             cnt <= cnt + 1;
6
         end if;
7
   end if;
8
end process;


Gibt es eine alternative Beschreibung, mittels derer der Zähler beim 
Maximalwert stehenbleibt, man jedoch keinen Komparator verwenden muss?

Grüsse, Harry
(Firma: www.dossmatik.de) #2467593
Lesenswert?

> Gibt es eine alternative Beschreibung, mittels derer der Zähler beim
> Maximalwert stehenbleibt, man jedoch keinen Komparator verwenden muss?
>

Ich weiss nicht, was dich dabei stört? Oder was genau dein Problem ist.
Dein Code muss noch zwei Sachen sinnvoller Weise beinhalten.
--ein Wert von wo aus gezählt wird
--Rücksetzmechanismus
#2467827
Lesenswert?

JBB schrieb:
> Wenn der Zähler so gestrickt ist, dass der Endwert eine Binärzahl ist
> und er rückwärtsläuft, dann ist der "Komparator" nur ein einziges Bit,
> dass den enable des Zählers freigibt.

Ach, geh...
Der Komparator ist immer über die volle Breite, weil alle Bits gestestet 
werden müssen, ob sie 0 sind.
Es stimmt aber, dass ein Vergleich auf Gleichheit wahrscheinlich 
effizenter ist als ein Vergleich auf kleiner.
Ob er nach oben oder unten zählt ist egal.
Moderator (Firma: Titel) Persönliche Seite #2467844
Lesenswert?

Harry schrieb:
> Gibt es eine alternative Beschreibung, mittels derer der Zähler beim
> Maximalwert stehenbleibt, man jedoch keinen Komparator verwenden muss?
Nur, wenn du (wie schon erwähnt) eine Zweierpotenz hast, dann kannst du 
ein Bit mehr spendieren und diesen Überlauf (beim Hochzählen) zum 
Anhalten des Zählers verwenden...
Gast #2467876
Lesenswert?

Klaus Falser schrieb:
> JBB schrieb:
>> Wenn der Zähler so gestrickt ist, dass der Endwert eine Binärzahl ist
>> und er rückwärtsläuft, dann ist der "Komparator" nur ein einziges Bit,
>> dass den enable des Zählers freigibt.
>
> Ach, geh...
> Der Komparator ist immer über die volle Breite, weil alle Bits gestestet
> werden müssen, ob sie 0 sind.
> Es stimmt aber, dass ein Vergleich auf Gleichheit wahrscheinlich
> effizenter ist als ein Vergleich auf kleiner.
> Ob er nach oben oder unten zählt ist egal.

es geht aoch ohne all bits zu vergleichen:

1) One-Hot schieberegister verwenden, dann braucht man nur ein bit 
vergleichen

2) Zähler als binärinkrement bauen mit Maximalwert "alle bits '1'",
dann ist das carry_out der höchsten Zählerstelle das einzige zu testende 
bit.

MfG,
Gast #2468926
Lesenswert?

Was haltet ihr von folgender Variante?
Man lagert den Vergleich getaktet aus. Dabei muss man dafür sorgen, dass
aufgrund des Delays der Zähler rechtzeitig aufhört zu zählen.

Hintergrund meiner Überlegungen: Für große Zähler möchte ich NICHT
Zähler und Komparator in einem Takt behandeln, um die Performance
zu steigern.
1
process(clk)
2
begin
3
    if rising_edge(clk) then
4
        if ena then
5
           cnt <= cnt + 1;
6
        end if;
7

8
        if cnt = cMAX-1 or cnt = cMAX then
9
           ena <= false;
10
        else
11
           ena <= true;
12
        end if;
13
    end if;
14
end process;


Grüsse, Harry
Moderator (Firma: Titel) Persönliche Seite #2469009
Lesenswert?

Harry schrieb:
> Man lagert den Vergleich getaktet aus.
Hört sich an wie: man lügt sich was in die Tasche...
Warum sollte da ein Vergleicher gespart werden?
Was ist denn eigentlich dein Ziel?

>     if cnt = cMAX-1 or cnt = cMAX then
Wie bitte?
Das solltest du dir nochmal überlegen.
Ich würde da einfach so schreiben:
   if cnt>=cMAX-1 then
Gast #2469037
Lesenswert?

Harry schrieb:
> Für große Zähler möchte ich NICHT
> Zähler und Komparator in einem Takt behandeln, um die Performance
> zu steigern.
Wie groß sollen denn Deine Zähler werden? Und wie schnell möchtest Du 
damit zählen. Üblicherweise sind in einem Design nicht die Zähler das 
limitierende Element.

Duke
Gast #2469243
Lesenswert?

>Hört sich an wie: man lügt sich was in die Tasche...
>Warum sollte da ein Vergleicher gespart werden?
>Was ist denn eigentlich dein Ziel?

OK, man spart keinen Vergleicher, sondern separiert Zähler und 
Komparator derart, dass die kombinatorische Logik kleiner wird.


>if cnt>=cMAX-1 then

ACK



>Was ist denn eigentlich dein Ziel?

Kombinatorik verkleinern und somit fMAX steigern.


Grüsse, Harry
Moderator (Firma: Titel) Persönliche Seite #2469316
Lesenswert?

Harry schrieb:
> OK, man spart keinen Vergleicher, sondern separiert Zähler und
> Komparator derart, dass die kombinatorische Logik kleiner wird.
Nein. Sie bleibt genau gleich. Denn es ist ja auch der selbe 
Vergleicher (es steht ja auch genau der selbe VHDL-code da)...

Harry schrieb:
> Kombinatorik verkleinern und somit fMAX steigern.
Du kannst mit dem Einfügen von zusätzlichen Registern und dem Aktivieren 
von "Register Balancing" eventuell Taktfrequenz gegen Latenz 
eintauschen. Aber dein Vergleicher wird in der Summe niemals 
"schneller":
Wenn der 8 Logikebenen hat, dann kannst du z.B. in die 4. Ebene einen 
Zwischenspeicher einfügen und dadurch die Taktfrequenz (fast) 
verdoppeln. Dein Vergelich ist dann aber erst nach 2 Takten fertig....
Gast #2469331
Lesenswert?

>Nein. Sie bleibt genau gleich

Das ist so aber nicht richtig, denn ich generiere mir ein getaktetes
Enable-Signal und verwende dieses statt des Komparators für den 
Zählvorgang.
Durch das Enable-Signal habe ich die Kombinatorik gesplittet.
Moderator (Firma: Titel) Persönliche Seite #2469365
Lesenswert?

Harry schrieb:
> Das ist so aber nicht richtig, denn ich generiere mir ein getaktetes
> Enable-Signal und verwende dieses statt des Komparators für den
> Zählvorgang.
> Durch das Enable-Signal habe ich die Kombinatorik gesplittet.
Hast du dir den RTL-Plan mal angeschaut? Dieses zusätzliche Flipflop 
sitzt einfach hinter dem gleichen Vergleicher und bringt dir 1 Takt 
Latency. Sonst ändert sich nichts.
Gast #2469380
Lesenswert?

Hier noch der VHDL-Code, mit dem ich das getestet habe
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4

5

6
entity komparator is
7
port(
8
  reset : in  std_logic;
9
  clk : in  std_logic;
10
  sig : out std_logic
11
);
12
end komparator;
13

14

15

16
architecture rtl of komparator is
17

18
signal cnt : unsigned(15 downto 0);
19
signal ena : std_logic;
20

21
begin
22

23
process(reset, clk)
24
begin
25
  if reset = '1' then
26
    cnt <= (others => '0');
27
    ena <= '0';
28
  
29
  elsif rising_edge(clk) then
30
    if (ena = '1') then  -- Splittung der Kombinatorik
31
      cnt <= cnt + 1;
32
    end if;
33
    
34
    -- if cnt < 2**16-1 then-- Komparator und zähler zusammen
35
      -- cnt <= cnt + 1;
36
    -- end if;
37
    
38
    if cnt >= 2**16-2 then
39
      ena <= '1';
40
    else
41
      ena <= '0';
42
    end if;
43
  end if;
44
end process;
45

46

47
sig <= cnt(12) when rising_edge(clk);
48

49

50
end architecture;
Moderator (Firma: Titel) Persönliche Seite #2469464
Lesenswert?

Harry schrieb:
> Mit welchem Tool kann man sich die Praxis im FPGA denn anschauen?
Das ist der RTL-Schaltplan. Wie du den bekommst, das kommt auf den 
Synthesizer an. Mit XST geht es seit der Version 13 gar nicht mehr: das 
Ding vergisst einfach, die Module miteinander zu verbinden.. :-(

Dann kommt mit dieser Beschreibung nur noch sowas raus wie im Anhang...
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4

5
entity cto is
6
    Port ( clk : in  STD_LOGIC;
7
           o   : out STD_LOGIC_VECTOR(7 downto 0)
8
          );
9
end cto;
10

11
architecture Behavioral of cto is
12
  signal cnt : integer := 0;
13
  constant cMAX : integer := 8;
14
begin
15

16
  process(clk)
17
  begin
18
    if rising_edge(clk) then
19
        if cnt/=cMAX then
20
           cnt <= cnt + 1;
21
        end if;
22
    end if;
23
  end process;
24

25
  o <= std_logic_vector(to_unsigned(cnt,8));
26

27
end Behavioral;

Lattice User schrieb:
> fMax gegen Latency getauscht.
Richtig, und das kann man machen, solange man noch einen Takt "Luft" 
hat.
Angehängte Dateien:
Gast #2469473
Lesenswert?

Die funktionale Simulation zeigt mir, dass beide Varianten bei 0xFFFF 
aufhören zu zählen.



1
library ieee;
2
use ieee.std_logic_1164.all;
3

4

5
entity tb_komparator is
6
end entity;
7

8
architecture testbench of tb_komparator is
9

10

11
signal clk : std_logic := '0';
12
signal reset : std_logic := '1';
13

14
begin
15

16

17

18
uut: entity work.komparator
19
port map(
20
  reset => reset,
21
  clk => clk,
22
  sig => open
23
);
24

25

26

27

28
bCLK: block
29
begin
30
  clk <= not clk after 10 ns;
31
end block;
32

33

34
bRST: block
35
begin
36
  reset <= '0' after 33 ns;
37
end block;
38

39

40
end architecture;



Kleine Korrektur noch im eigentlichen Modul:
1
if cnt >= 2**16-2 then
2
    ena <= '0';
3
else
4
    ena <= '1';
5
end if;
Gast #2469485
Lesenswert?

Hier ein Modelsim-Screenshot.


Leicht modifizierter Code (cnt2 hinzugekommen):
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4

5

6
entity komparator is
7
port(
8
  reset : in  std_logic;
9
  clk : in  std_logic;
10
  sig : out std_logic
11
);
12
end entity;
13

14

15

16
architecture rtl of komparator is
17

18
signal cnt : unsigned(15 downto 0);
19
signal cnt2 : unsigned(15 downto 0);
20
signal ena : std_logic := '0';
21

22
begin
23

24
process(reset, clk)
25
begin
26
  if reset = '1' then
27
    cnt <= (others => '0');
28
    cnt2 <= (others => '0');
29
    ena <= '1';
30
  
31
  elsif rising_edge(clk) then
32
    if (ena = '1') then          -- Splittung der Kombinatorik
33
      cnt <= cnt + 1;
34
    end if;
35
    
36
    
37
    if cnt2 < 2**16-1 then      -- Komparator und zähler zusammen
38
      cnt2 <= cnt2 + 1;
39
    end if;
40
    
41

42
    
43
    if cnt >= 2**16-2 then
44
      ena <= '0';
45
    else
46
      ena <= '1';
47
    end if;
48
  end if;
49
end process;
50

51

52
sig <= cnt(12) when rising_edge(clk);
53

54

55
end architecture;
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #2469497
Lesenswert?

Harry schrieb:
> if cnt2 < 2**16-1 then      -- Komparator und zähler zusammen
>     if cnt >= 2**16-2 then
Ja. Das ist Latency...  ;-)

Es macht übrigens in der Realität auch was aus, ob du das schreibst:
  if cnt2 <  2**16-1 then
Oder das:
  if cnt2 != 2**16-1 then
Und das, obwohl die Funktion hier exakt gleich ist: es wird gezählt 
solange cnt kleiner als 65535 ist.
Gast #2469510
Lesenswert?

Fakt ist: "cnt" und "cnt2" verhalten sich identisch.

Fakt ist auch: Die "cnt"-Variante kann ein höheres fmax fahren.


Ergo: Für Performance ist die cnt-Variante mit Enable die Bessere.


Grüsse, Harry
Gast #2469558
Lesenswert?

Harry hat zwar Latenz erzeugt (und idR auch mehr Logik+FF),
bei ZMAX>>1 ist das mit der Latenz aber egal, wei's nur
zählerintern gebraucht wird. Und viel schneller lässt's sich
auch takten (Stopp hängt nur noch von einem Signal ab).

x /= y bzw. x < y:
bei modernen FPGAs (Xilinx,Altera CarryChains) ist das bei
idealer Implementierung gleich aufwendig, Synthesetools
sollte es aber auch können.
Gast #2469560
Lesenswert?

Harry schrieb:
> Ergo: Für Performance ist die cnt-Variante mit Enable die Bessere.

Streitet niemand ab.
Man muss nur die Latency beachten, ich habe übersehen dass du genau 
deswegen auf einen anderen Endwert vergleichst.

IMO geht noch mehr:
Keinen < Vergleich verwenden um die Komplexität des Vergleichs zu 
reduzieren.
Beim Resetwert des Zählers kompensieren und nur auf Überlauf abfragen (1 
bit vs viele).

Im Technology View von Synplify kann man sehen wie das ganze auf die 
FPGA Primitiven abgebildet wird.
Gast #2469764
Lesenswert?

@Lothar Miller,

>> x /= y bzw. x < y:
>..
> Leider nein...

doch, zumindestens bei Xilinx Spartan3/Virtex4 (LUT4-CarryChain)
und Virtex5 (LUT5/6+CarryChain) bin ich mir sicher, habe mal die
CarryChain-Logik in eine Gleichung gefasst um das max. Mögliche
für mich zu ermitteln. Daraus habe ich dann die Gleichungen für
eine Menge von Operationen (ADD/SUB/CMP etc.) ermittelt. Vorteil
von CMP ist ausserdem, dass gleichzeitig le LUT 2Bits mit 2Bits
verglichen werden können (sozusagen braucht man nur die
"halbe Länge" an CarryChain).
Gast #2469985
Lesenswert?

Mein Ansatz funktioniert ab ISE 5.1 (?), 6.1 sicher.
Allerdings benutze ich das Synthesetool nur für
die Instanziierung der Spartan3/Virtex4-Komonenten
(LUT4/FF/CARRYCHAIN etc.), d.h. die komplette Logik
muss von Hand erstellt werden (geht aber sehr leicht,
insb. generisch). Angewendet habe ich es z.B. in einer
eigenen CPU, die im Virtex4 (10er Speedgrade) mit
400 MHz läuft.

Von ISE selber kannst du eine solche Performance nicht
erwarten, selbst Harry's Ansatz mit dem vorgezogenen
Vergleich liefert eine laue Leistung.
Das zeigt mal wieder, wie mittelmässig ISE (Quartus
kenne ich kaum) einfach zu erkennende Konstrukte in
die Fabrikeigene Logik giessen kann.

Gruss

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren