Forum: FPGA, VHDL & Co. Wie einen Counter mit JK flipflops in VHDL beschreiben?


von Patrick M. (Firma: na) (bitdiver)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche eine Operation wie diese in HW zu giessen:

   n = n + 1


wobei n vom Typ std_logic_vector(4 downto 0) wäre.

Jetzt habe ich schon festgestellt dass für Zählen in HW Flipflops 
benötigt werden. D.h. ich müsstse den Zustand verschiedener Signale 
definieren, um einen Zählvorgang zu beschreiben.

1) Ich brauch FlipFlops - wo liegt der Unterschied ob ich D oder JK 
Flipflops hernehme?
2) In einem alten Datasheet ist die Schaltung mit JK FF implementiert, 
und vornedran werden auf dem D Signal ein paar Signale verodert und 
verundet - wie ist dieser "Selekter" zu verstehen?

Besten Dank für eine kleine Starthilfe bei der Aufgabe, den Zähler zu 
bauen.

: Bearbeitet durch User
von Vancouver (Gast)


Lesenswert?

JK-FFs sind aus dem Pleistozän der Digitaltechnik. Heute werden nur noch 
D-FFs verwendet. Die Funktion ist denkbar einfach: Der Wert am D-Eingang 
wird mit der aktiven Taktflanke an den Ausgang Q übernommen.
Für den Zähler überleg jetzt mal, wie du von einem Zählerstand zum 
nächsten kommst, daraus ergibt sich die Schaltung praktisch von selbst.

von HildeK (Gast)


Lesenswert?

Vorneweg: ich kann kein VHDL.

Patrick M. schrieb:
> 1) Ich brauch FlipFlops - wo liegt der Unterschied ob ich D oder JK
> Flipflops hernehme?
Mit JK-FF hast du mehr Möglichkeiten. Im Prinzip kannst du aber beide 
nehmen. Mit welcher Variante du einfacher wegkommst, hängt auch davon 
ab, ob du einen synchronen oder einen asynchronen Zähler bauen willst. 
Beim synchronen ist meiner Erinnerung nach der Aufwand beim 
Bereitstellen der richtigen JK-Signale einfacher.

> 2) In einem alten Datasheet ist die Schaltung mit JK FF implementiert,
> und vornedran werden auf dem D Signal ein paar Signale verodert und
> verundet - wie ist dieser "Selekter" zu verstehen?
Daran siehst du, was für ein Aufwand getrieben wird, um aus einem JK-FF 
ein D-FF zu machen. Die Gatter sind einfach notwendig, um das korrekte 
D-Signal, das ja bei einem Zähler auch abhängig vom FF-Ausgang ist, 
richtig zu generieren.
Schau dir doch einfach mal in den Datenblättern die Wirkung von JK- bzw. 
D-Signalen auf das Schalten von FFs an.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Patrick M. schrieb:
> 1) Ich brauch FlipFlops - wo liegt der Unterschied ob ich D oder JK
> Flipflops hernehme?

Bei D-Flipflops brauchst du 5 Schaltnetze mit jeweils 5 Eingaengen und 
einem Ausgang, bei denen gibt es aber keine don't care Kombinationen.

Bei JK-Flipflops brauchst du 10 Schaltnetze mit jeweils 5 Eingaengen und 
einem Ausgang, da werden aber "don't care" Kombinationen auftauchen, 
d.h. wahrscheinlich werden die "einfacher" ausfallen. Dafuer halt 
doppelt so viele.

Gruss
WK

von Markus F. (mfro)


Lesenswert?

Patrick M. schrieb:
> Jetzt habe ich schon festgestellt dass für Zählen in HW Flipflops
> benötigt werden. D.h. ich müsstse den Zustand verschiedener Signale
> definieren, um einen Zählvorgang zu beschreiben.

Wenn Du digitale Schaltungstechnik lernen möchtest, ist das der richtige 
Ansatz. Wenn Du VHDL lernen möchtest, eher nicht. Da heißt das:
1
n <= std_logic_vector(unsigned(n) + 1) when rising_edge(clk);

oder eben in einem Prozess, wenn dir das lieber ist. Die Tools erledigen 
den Rest für dich.

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


Lesenswert?

Patrick M. schrieb:
> Jetzt habe ich schon festgestellt dass für Zählen in HW Flipflops
> benötigt werden.
Du kannst mit VHDL zwar JK-Flipflops beschreiben. Du kannst sie aber 
nicht in FPGAs einbauen, weil es dort keine gibt.

> 1) Ich brauch FlipFlops - wo liegt der Unterschied ob ich D oder JK
> Flipflops hernehme?
Wenn du mit deiner Beschreibung auf ein FPGS oder ein CPLD willst, dann 
musst du D-Flipflops nehmen. Denn nur solche hast du auf dieser 
Zielplattform zur Verfügung.

Oder andersrum: du kannst zwar irgendwas mit 50mm langen Schrauben auf 
ein Blatt Papier zeichnen. Wenn du in deiner Kiste aber nur 30mm lange 
Schrauben hast, dann kannst du es nicht wie gewünscht aufbauen.

> D.h. ich müsstse den Zustand verschiedener Signale definieren, um einen
> Zählvorgang zu beschreiben.
Nein, in VHDL nimmst du einfach den '+' Operator um einen Zählvorgang zu 
beschreiben. Natürlich kannst du auch deine eigene Zählerfortschaltlogik 
machen, aber die ist trotzdem sicher langsamer als das simple '+' 
Zeichen. Markus F. schrieb:
> Die Tools erledigen den Rest für dich.
Denn mit einem '+' kann der Synthesizer umgehen und die 
Addierer-Strukturen im FPGA verwenden. Eine selbst handgestrickte Logic 
setzt er aber umständlich in LUTs und Verdrahtung um.

Huer noch die Lösung mit dem Prozess:
1
   process begin
2
      wait until rising_edge(clk);
3
      n <= n+1; -- verwendet die flotte Carrychain
4
   end process;

von Markus F. (mfro)


Lesenswert?

Lothar M. schrieb:
> Nein, in VHDL nimmst du einfach den '+' Operator um einen Zählvorgang zu
> beschreiben. Natürlich kannst du auch deine eigene Zählerfortschaltlogik
> machen, aber die ist trotzdem sicher langsamer als das simple '+'

die Carry-Chain Lowlevel Primitive kann man auch "per Hand" bedienen 
(langsamer ist der "handgestrickte" Zähler also nicht notwendigerweise).

Aber warum sollte man das tun, wenn's ein einfaches "+" auch tut?

von Patrick M. (Firma: na) (bitdiver)


Angehängte Dateien:

Lesenswert?

Vielen Dank für eure Hilfe. Verstehe, die Flipflops explizit für einen 
Counter im VHDL zu beschreiben ist nicht nötig. Dann lasse ich die mal 
in der Schublade (oder auf dem Blatt Papier für andere Projekte) und 
konzentriere mich ganz auf einen Counter durch '+'

Mein Versuch aktuell sieht so aus:

VHDL für den Counter:
1
LIBRARY ieee;
2
3
USE ieee.std_logic_1164.ALL;
4
USE ieee.numeric_std.ALL;
5
6
entity Counter is port (                   
7
   clk:  in std_logic;   -- clock
8
   -- ... mehr controls kommen spaeter
9
   q:    out std_logic_vector(3 downto 0);                  
10
   TC:   out std_logic  -- trickle, carry out oder so
11
);                
12
end Counter;
13
14
15
architecture arc of Counter is
16
17
18
begin
19
20
  q <= std_logic_vector(unsigned(q) + 1) when rising_edge(clk);
21
22
end architecture arc ;


Und eine erste Testbench, die nur versucht den Zählvorgang zu triggern:

1
library ieee;
2
3
use ieee.std_logic_1164.all ;
4
5
6
entity tb is begin
7
end ;
8
9
10
11
architecture tb_behav of tb is
12
 
13
   component Counter is port (
14
      clk:   in std_logic;   -- clock
15
      Q:    out std_logic_vector(3 downto 0);                  
16
      TC:   out std_logic  -- Terminal Count
17
  );
18
   end component ;
19
 
20
   signal tb_CLK : std_logic := '0';
21
   signal tb_Q : std_logic_vector(3 downto 0) := "0000";
22
   signal tb_TC : std_logic := '0';
23
 
24
 
25
 begin
26
 
27
     dut : Counter port map (
28
       clk => tb_clk,
29
       Q => tb_Q , 
30
       TC => tb_TC 
31
     );
32
 
33
   clk_proc: process begin
34
 
35
     CLK <= not CLK;
36
     wait for 5 ns;
37
   
38
     if NOW > 200 ns then
39
       wait;
40
     end if;
41
   end process clk_proc;
42
 
43
   stim_proc : process begin
44
    
45
 
46
     wait for 80 ns ;
47
48
     wait ;
49
50
   end process;
51
 
52
end architecture tb_behav ;

Mit Ghdl --std=08 analyze und elaborate bekome ich die Waveform wie im 
Anhang. Leider sehe ich noch keinen Effekt vom '+' im Q bus. Bin nun 
etwas verwirrt....

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Tipp: welchen Wert hat q (in der Entity) beim Start?

und welchen Wert hat es, wenn man 1 auf diesen Wert aufaddiert?

Willkommen in der Welt der 5-wertigen Logik.

von Patrick M. (Firma: na) (bitdiver)


Angehängte Dateien:

Lesenswert?

Ja, der Groschen ist gefallen. Danke.
Ich habe ein Reset Signal eingefügt mit dem q <= "0000" gesetzt werden 
kann.
Zuerst dachte ich der reset sei über ein VHDL Konstrukt q := "0000" 
möglich. Ein extra Signal zum Reset sieht sauberer aus.

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


Lesenswert?

Patrick M. schrieb:
> Ich dachte der reset wäre über ein VHDL Konstrukt := "0000" möglich.
Man kann Initialwerte für Signale so vorgeben.

Aber eben nicht von der Testbench auf einen Ausgang des Prüflings! Du 
musst den Initwert im Modul vorgeben. In deinem Fall müsste das so 
aussehen:
1
entity Counter is port (                   
2
   :
3
   q :  out std_logic_vector(3 downto 0) := "0000";                  
4
   :
5
);
Aaaaaber:
Patrick M. schrieb:
> q:    out std_logic_vector(3 downto 0);
>   q <= std_logic_vector(unsigned(q) + 1) when rising_edge(clk);
Da kloppt dir hoffentlich der Synthesizer auf die Finger. Denn einen 
output Port kann man nicht lesen. Nimm ein lokales Signal zum Zählen und 
weise das dann dem Ausgang zu. Denn der schreibfaule Stil mit einem 
zurückgelesenen ouput oder buffer im Port ist halt nur faul. Keineswegs 
etwa schlau oder elegant.

Patrick M. schrieb:
> Der Reset sieht sauberer aus.
Ein Initwert ist auch vollkommen sauber, wenn man weiß, wo er hingehört. 
Für deinen Zähler würde ich einen unsigned Vektor zum zählen nehmen und 
dann den Zählerwert auf den Ausgang konvertieren und somit so schreiben:
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.ALL;
3
USE ieee.numeric_std.ALL;
4
5
entity Counter is port (                   
6
   clk:  in std_logic;   -- clock
7
   -- ... mehr controls kommen spaeter
8
   q:    out std_logic_vector(3 downto 0);                  
9
   TC:   out std_logic  -- trickle, carry out oder so
10
);                
11
end Counter;
12
13
architecture arc of Counter is
14
  signal cnt : unsigned (3 downto 0) := (others=>'0');
15
begin
16
17
  cnt <= cnt+1 when rising_edge(clk);
18
19
  q <= std_logic_vector(cnt);
20
21
end architecture arc ;

Hier noch ein paar Lösungen auf die Fragen, die
Markus F. schrieb:
> Tipp: welchen Wert hat q (in der Entity) beim Start?
Es hat den "linkesten" Wert seiner Deklaration. Bei einem std_logic ist 
das U für "Uninitialized".
https://www.cs.sfu.ca/~ggbaker/reference/std_logic/1164/std_logic.html

> und welchen Wert hat es, wenn man 1 auf diesen Wert aufaddiert?
Die Auflösungstabelle resolution_table gibt für 'U' mit irgendwas 
anderem wieder 'U' aus.
https://vhdlwhiz.com/std_logic-vs-std_ulogic/

> Willkommen in der Welt der 5-wertigen Logik.
Ein std_logic ist neunwertig....  ;-)

: Bearbeitet durch Moderator
von Markus F. (mfro)


Lesenswert?

Lothar M. schrieb:
> Da kloppt dir hoffentlich der Synthesizer auf die Finger. Denn einen
> output Port kann man nicht lesen.

VHDL 2008 (das der TO offensichtlich benutzt) erlaubt das (und ich 
find's gut)

Lothar M. schrieb:
> Markus F. schrieb:
>> Tipp: welchen Wert hat q (in der Entity) beim Start?
> Es hat den "linkesten" Wert seiner Deklaration. Bei einem std_logic ist
> das U für "Uninitialized".
> https://www.cs.sfu.ca/~ggbaker/reference/std_logic/1164/std_logic.html
>
Das ist richtig.

>> und welchen Wert hat es, wenn man 1 auf diesen Wert aufaddiert?
> Die Auflösungstabelle resolution_table gibt für 'U' mit irgendwas
> anderem wieder 'U' aus.
> https://vhdlwhiz.com/std_logic-vs-std_ulogic/

... nicht richtig:

"UUU" + 1 ergibt unmittelbar "XXX"

numeric_std-Funktionen ("+" ist eine) weisen sofort (ohne Meldung) "X" 
zu, wenn ihnen irgendwas seltsam vorkommt...

>> Willkommen in der Welt der 5-wertigen Logik.
> Ein std_logic ist neunwertig....  ;-)

Stimmt. Von den Neunen hab' ich einfach mal vier ignoriert, weil sie in 
freier Wildbahn praktisch nie vorkommen...

von Helmut S. (helmuts)


Lesenswert?

Lothar M. schrieb:
> begin
>
>   q <= cnt+1 when rising_edge(clk);
>
>   q <= std_logic_vector(cnt);
>
> end architecture arc ;

Das sollte doch bestimmt so aussehen:

   cnt <= cnt+1 when rising_edge(clk);

   q <= std_logic_vector(cnt);

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


Lesenswert?

Helmut S. schrieb:
> Das sollte doch bestimmt so aussehen:
Ja, latürnich, danke. Habs korrigiert...  ;-)

Markus F. schrieb:
> "UUU" + 1 ergibt unmittelbar "XXX"
>  numeric_std-Funktionen ("+" ist eine)
Stimmt, da kommt die Auflösungstabelle gar nicht zur Wirkung:
1
:
2
     -- Id: A.3
3
function "+" ( L,R: UNSIGNED ) return UNSIGNED is
4
constant SIZE: NATURAL:= MAX (L'LENGTH, R'LENGTH) ;
5
variable L01 : UNSIGNED(SIZE-1 downto 0);
6
variable R01 : UNSIGNED(SIZE-1 downto 0);
7
begin
8
  if ((L'length<1) or (R'length<1)) then return NAU; end if;
9
  L01 := TO_01(RESIZE(L,SIZE),'X');               -- von hier kommt das X
10
  if (L01(L01'left)='X') then return L01; end if;
11
  R01 := TO_01(RESIZE(R,SIZE),'X');               -- und von hier
12
  if (R01(R01'left)='X') then return R01; end if;
13
  return ADD_UNSIGNED (L01, R01, '0') ;
14
  end;
15
:
Aus https://www.csee.umbc.edu/portal/help/VHDL/packages/numeric_std.vhd

Markus F. schrieb:
> VHDL 2008 (das der TO offensichtlich benutzt) erlaubt das
Der Verdacht mit VHDL2008 liegt nahe.

> (und ich find's gut)
Naja, es bringt eben genau solche unnötige Verwirrung ins Spiel, dass 
für manche Ports in der Portdeklaration Intitialwerte angegeben werden 
können (für diejenigen eben, die speichern können). Und das führt 
garantiert zu Verwirrungen.

Ich deklariere lokale Signale, belege sie mit Initwerten (wenn nötig), 
rechne mit ihnen, und weise sie zum Schluss an Ports nach aussen zu 
(wenn nötig). Immer alles gleich und geradlinig... ;-)

: Bearbeitet durch Moderator
von Zeno (Gast)


Lesenswert?

Vancouver schrieb:
> JK-FFs sind aus dem Pleistozän der Digitaltechnik. Heute werden nur noch
> D-FFs verwendet.

Das ist natürlich völliger Quatsch. JK ist viel flexibler als 
D-Flipflop. Beim JK-FF bestimmt der Logikpegel an den JK-Eingängen wie 
der dem Taktimpuls folgende Ausgangszustand aussieht. Da es i.d.R. immer 
mehrere AND oder NAND verknüpfte Eingänge gibt spart das meist auch noch 
zusätzliche Gatter.
Synchronzähler z.B. lassen sich nur mit JK-FF realisieren.

@TO
Wenn Du was über Flipflop Schaltungstechnik lernen möchtest, dann 
empfehle ich Dir Kühn/Schmied "Handbuch integrierte Schaltkreise". Das 
Buch war seinerzeit der Tietze/Schenk der TTL-Schaltkreistechnik. Auch 
wenn TTL-Schaltkreise schon lange überholt sind, aber die Grundlagen 
logischer Schaltkreise und Schaltungen gelten nach wie vor. Genau 
deshalb kann ich Dir dieses Buch nur wärmsten empfehlen. Danach sollte 
die Implementation eines Zählers in VHDL nur noch ein Kinderspiel sein. 
Das Buch beschreibt auch wie man so ein FF aus Gattern aufbauen kann. 
Ebenso werden verschiedene Zähler und Codecs behandelt. Alles mit 
Standardgattern, JK-FF und auch D-FF. Bestimmte Sachen gehen aber eben 
nur mit JK-FF.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Zeno schrieb:
> Synchronzähler z.B. lassen sich nur mit JK-FF realisieren.

Bei der Aussage meld' ich doch mal ganz leise Zweifel an.

Gruss
WK

von Vancouver (Gast)


Lesenswert?

Zeno schrieb:
> JK ist viel flexibler als
> D-Flipflop.

Dann erklär uns doch mal, ws man mit einem JK-FF machen kann, was mit 
einem D-FF nicht geht.

Zeno schrieb:
> Beim JK-FF bestimmt der Logikpegel an den JK-Eingängen wie
> der dem Taktimpuls folgende Ausgangszustand aussieht.

Beim D-FF bestimmt der Logikpegel am D-Eingang, wie der dem Taktimpuls 
folgende Ausgangszustand aussieht. Und?

Zeno schrieb:
> Da es i.d.R. immer
> mehrere AND oder NAND verknüpfte Eingänge gibt spart das meist auch noch
> zusätzliche Gatter.

... die dann dafür im JK-FF drinstecken.

Zeno schrieb:
> Synchronzähler z.B. lassen sich nur mit JK-FF realisieren.

Also das ist völliger Quatsch. Die oben beschriebene 
Zählerimplementierung ist synchron, weil alle D-FFs den gleichen Takt 
bekommen, und selbst asynchrone Zähler sind einfacher mit D-FFs zu bauen 
- ganz ohne zusätzliche Gatter.
Ich kenne keine FPGAs und keine ASIC-Standardzellenbibliothek, in der 
noch JK-FFs verfügbar sind (weiß jemand, ob es sowas gibt?)
Wenn man entsprechend masochistisch veranlagt ist, kann man natürlich in 
VHDL oder Verilog ein JK-FF definieren und dann daraus einen Zähler oder 
eine Statemachine bauen (ich will gar nicht darüber nachdenken, wie der 
Code aussähe...), aber die Logiksynthese wird den den ganzen 
Gatterverhau optimieren und wieder D-FFs daraus machen.

JK-FFs werden heute nur noch verwendet, um Informatiker im ersten 
Semster zum Nachdenken anzuregen (was zugegeben nicht das Schlechteste 
ist), aber ansonsten sind die weg vom Fenster.

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.