Forum: FPGA, VHDL & Co. use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL;


von erschlagen (Gast)


Lesenswert?

Hallo,

ich benötige noch einmal eure Unterstützung, bin nämlich immer noch 
ziemlich erschlagen.
Ich habe vor einigen Wochen als ich mit vhdl begonnen habe, 
std_logic_unsiged verwendet und da hatten std_logic vektoren für Zähler 
wie unten funktioniert.
da ich vernommen habe, daß obige packages empfehlenswerter sind, habe 
ich mir vorgenommen, diese auch zu verwenden aber sie treiben mich in 
den Wahnsinn, denn intuitiv komme ich nie ans Ziel.

2 fragen: wo ist bei folgendem mein Denkfehler und wo finde ich eine 
Übersicht, was ich wie wohin konvertieren kann/muss und wie ich 
vektoren, integers verwalte.

Schlagt mich nicht, wenn das über die Maßen idiotisch und banal ist.
1
signal nibble : natural range 0 to 3 := 0;
2
(.....)
3
choose_nibble : process (clk, clk_enable) begin
4
  if rising_edge(clk) then
5
    if(clk_enable = '1') then
6
      nibble <= nibble + 1;
7
    end if:
8
  end if;
9
end process;

von erschlagen (Gast)


Lesenswert?

Ach ja: mit nibble passiert noch gar nichts weiter. Soll später 
-logisch- ein Nibble zur Anzeige bringen ich habe aber zuerst nur ein 
Signal was rund zählen soll gemacht. Aus Respekt vor den Fehlern.

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


Lesenswert?

Nimm integer:
>> signal nibble : integer range 0 to 3 := 0;
Und dann kannst du hin und her konvertieren und casten:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std


>> process (clk, clk_enable) begin
Hierreicht clk in der Sensitivliste aus, denn der Prozess muß nur dann 
neu berehnet werden, wenn clk sich ändert.

EDIT:
Hat ein Nibble bei dir 4 Bits?
Dann müsste das ein
integer range 0 to 15 := 0;
sein. Alternativ z.B. ein
unsigned(3 downto 0) := "0000";

von erschlagen (Gast)


Lesenswert?

schäm nach einiger Zeit auf dem Balkon ist mir der ":"<->";" Ärger 
doch selber aufgefallen. ich habe ungelogen über eine Stunde darüber 
gebrütet... :-(
Nichtsdestotrotz bleibt die Frage: was macht man denn nun mit integers, 
unigneds und std_logic_vecrtors und wann castet man wohin?

Werde zusehen den thread nicht weiter mit Folgeposts zu verseuchen - da 
wäre mal anmelden sinnvoll, daß editieren möglich ist. Entschuldigung.

von erschlagen (Gast)


Lesenswert?

danke.

Noch eine konkrete Frage:

angenommen ich habe so einen
1
digit_sel : integer range 0 to 3
Sowie ein
1
 digit : std_logic_vector(3 downto 0);

Damit soll aus einem 8 Bit Zähler
1
counter : natural range 0 to 2**16-1
 immer ein Nibble (ja dachte das wären quasi genormt 4 bit) 
ausgeschnitten und angezeigt werden. Dabei dachte ich an so etwas wie 
unten außerhalb eines prozesses, der das Signal "nibble" anzeigt. Stelle 
würde auch noch ausgewählt es geht mir gerade um das auswählen, welches 
nicht recht klappen will.
1
width digit_sel select
2
digit <= counter(3 downto 0) when 0, <= counter(7 downto 4) when 1, <=counter(11 downto 8) when 2, counter(15 downto 12) when others.

counter müsste dort wohl in std_logic_vector gecastet werden? Eben das 
verwirrt mich. Würde man noch ein Signal für den gecasteten 
interger/unsigned vorsehen? ist die Denke überhaupt richtig und kann man 
davon ausgehen, daß die Schreibweise und verwendung von zig Signalen 
bzw. aufteilung in Prozesse und außerprozess Abarbeitung keinen Einfluss 
auf Größe/Geschwindigkeit hat? Es kommen ja auch größere Projekte... 
Lesbar wird das glaube ich nicht.

Aber zunächst wäre ich glücklich über Erleuchtung bei dem simplen 
Beispiel.

von Iulius (Gast)


Lesenswert?

Du musst dich immer fragen auf welchem Level du denken willst.

Bsp : ich nutze für Zähler grundsätzlich unsigned und zwar aus dem 
Grund, das ich mir damit genau das in der Hardware vorstelle was ich 
auch beschreibe : einen Zähler mit exakt so viel Bits wie in der 
Definition angegeben der bei 111...1 überläuft.

Natural hingegen baut je nach Range gleich noch Logik zum Reset auf 0 an 
einer bestimmten Position(maximum) ein.

Dementsprechend kann es auch nicht direkt ausgegeben werden, z.b. auf 
Pins, denn die Logik die dahinter steckt ist nicht mehr exakt definiert. 
(in der Folge natürlich schon, deswegen kann man es ja auch 
konvertieren, aber im ersten Moment für die Sprache VHDL an sich nicht)

Bei unsigned ist das kein Problem, da es genau das gleiche Format wie 
std_logic_vector hat, demzufolge ist keine Konvertierung nötig sondern 
lediglich eine Umbenennung des Typs.

bsp :

signal x : unsigned(15 downto 0);
y <= std_logic_vector(x(3 downto 0));

Merke : kein "to_std_logic_vector"

Bei naturals oder integer kommt eben eine Umwandlung vor, hauptsächlich 
um zu klären wie breit denn die zu erzeugende Zahl überhaupt ist.

Wie das funktioniert kannst du den zugrunde liegenden Packages(also jene 
die du einbindest) entnehmen.


Deine With-select Anweisung ist somit schon ok, aber ein simples 3 
downto 0 ist wohl eher etwas für eine unsigned als für eine natural.

Und ob du mit integer oder auch mit unsigned selecten willst bleibt dir 
überlassen.

Anzumerken sei jedoch das dies durchaus einen Unterschied machen kann.


Bsp : mit unsigned kannst du problemlos ein Bit alleine zum selecten 
nutzen.
digit <= counter(3 downto 0) when digit_sel(0)='1' else...

Was in der Hardware deutlich schneller ist als eine Überprüfung auf die 
volle Range von digit_sel.

Das macht zwar bei einer 2 Bit breiten zahl keinen großen Unterschied, 
bei breiten select Anweisungen hingegen schon.

Natürlich kann man sich auch auf den Synthesizer verlassen, was aber 
nicht immer klappt (etwa wenn das select von außen kommt).



Du siehst also : da gibts Unmengen von Möglichkeiten. Deine Aufgabe ist 
es nun das für dich heraus zu ziehen von dem du meinst es nutzen zu 
wollen.

Für den Anfang hilft es z.b. schon mal jede Variante aufzuschreiben, zu 
simulieren und zu synthetisieren und sich die Unterschiede im RTL-Viewer 
sowie in der Hardwareauslastung anzusehen.

Was man dabei lernt kann einem niemand mal eben aufschreiben.

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


Lesenswert?

Du mußt den counter erst mal in einen Vektor wandeln, dann die Bits 
auswählen und dann auf den std_logic_vector casten:
1
with digit_sel select
2
   digit <= std_logic_vector(to_unsigned(counter,4)(3  downto  0)) when 0, 
3
            std_logic_vector(to_unsigned(counter,4)(7  downto  4)) when 1, 
4
            std_logic_vector(to_unsigned(counter,4)(11 downto  8)) when 2, 
5
            std_logic_vector(to_unsigned(counter,4)(15 downto 12)) when others;
Lesbarer wäre es, den Zähler erst in einen Vektor umzuwandeln und dann 
die Bits auszuwählen:
1
signal countvec : std_logic_vector (15 downto 0);
2
:
3
countvec <= std_logic_vector(to_unsigned(counter,16);
4
with digit_sel select
5
   digit <= countvec(3 downto 0) when 0, 
6
            countvec(7 downto 4) when 1, 
7
            countvec(11 downto 8) when 2, 
8
            countvec(15 downto 12) when others;
Eine dritte Möglichkeit ist den cnt erst mal zurechtrechnen und dann 
wandeln:
1
with digit_sel select
2
   digit <= std_logic_vector(to_unsigned(counter,     4) when 0, 
3
            std_logic_vector(to_unsigned(counter/16,  4) when 1, 
4
            std_logic_vector(to_unsigned(counter/256, 4) when 2, 
5
            std_logic_vector(to_unsigned(counter/1024,4) when others;


BTW:
1
   counter : natural range 0 to 2**16-1
natural ist ein eingeschränkter integer Tap. Wenn du den natural sowieso 
weiter einschränkst, dann nimm doch einfach gleich den Basistyp:
1
   counter : integer range 0 to 2**16-1

EDIT:
Iulius schrieb:
> Bsp : ich nutze für Zähler grundsätzlich unsigned
Ich verwende für Zähler nur eingeschränkte integer, und weiß implizit, 
dass die als eine bestimmte Anzahl FF realisiert werden. Dann sehe ich 
auch in der simulation gleich, wenn der Zähler mal Werte annimmt, für 
die er eigentlich nicht ausgelegt ist.

> Natural hingegen baut je nach Range gleich noch Logik zum Reset auf 0 an
> einer bestimmten Position(maximum) ein.
Das stimmt nicht.
1
signal cnt : integer range 0 to 511 := 0;
2
:
3
   process begin
4
     wait until rising_edge(clk);
5
     if (cnt<511) then cnt <= cnt + 1;
6
     else              cnt <= 0;
7
     end if;     
8
   end process;
Dieser integer-Zähler wird trotz der explizit beschriebenen 
Rücksetzbedingung exakt gleich implementiert wie der Verktor-Zähler mit 
seiner impliziten Rücksetzung:
1
signal cnt : unsigned (8 downto 0) := (others=>'0');
2
:
3
   process begin
4
     wait until rising_edge(clk);
5
     cnt <= cnt + 1;
6
   end process;
Für die Hacker unter uns, die ohne Simulation auskommen:
auch das hier wird genau gleich in Hardware abgebildet
1
signal cnt : integer range 0 to 511 := 0;
2
:
3
   process begin
4
     wait until rising_edge(clk);
5
     cnt <= cnt + 1;
6
   end process;

Von unschlagbarem Vorteil ist der /integer/-Zähler, wenn Vergleiche mit 
dem Zählerwert gemacht werden:
1
signal cnt : integer range 0 to 511 := 0;
2
: 
3
   if (cnt = 234) then
4
    :
Beim Vektor-Zähler ist hier eine umständliche Wandlung nötig:
1
signal cnt : unsigned (8 downto 0) := (others=>'0');
2
:
3
   if (cnt = to_unsigned(234,cnt'length)) then
4
     :

von Iulius (Gast)


Lesenswert?

>> Dieser integer-Zähler wird trotz der explizit beschriebenen
>> Rücksetzbedingung exakt gleich implementiert...

Ist ja auch kein Wunder bei der Range, was soll er da auch sonst tun ?
Versuch das mal mit einer Range die nicht direkt an einer Bitgrenze 
endet.

Zumal ich keinen Vorteil sehe in einer Integer die ich mit 0 bis 511 
einsetze anstatt einer 8 bis 0 unsigned.


>> Beim Vektor-Zähler ist hier eine umständliche Wandlung nötig:

wüsste nicht warum.
1
signal cnt : unsigned (8 downto 0) := (others=>'0');
2
...
3
   if cnt = 234 then

funktioniert wunderbar mit dem IEEE.NUMERIC_STD



Wie gesagt, dazu wirds 10 verschiedene Meinungen geben. Letztendlich 
muss jeder für sich entscheiden wie er arbeiten will.

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


Lesenswert?

Iulius schrieb:
> Ist ja auch kein Wunder bei der Range, was soll er da auch sonst tun ?
> Versuch das mal mit einer Range die nicht direkt an einer Bitgrenze
> endet.
Genau dann erkenne ich in der Simulation, wenn der Zähler aus dem 
definierten Bereich hinausläuft.
Bei einem 640x480 Display sind z.B. die Werte 479 und 639 interessant. 
Klar, dass auch ein integer range 0 to 479 in der Implementierung 9 
Bits braucht. Aber wenn der Index tatsächlich mal 480 wird, sagt mir das 
die Simulation. Bei einem unsigned (8 downto 0) wird weitergezählt bis 
nach 511 der implizite Überlauf kommt.

>>> Beim Vektor-Zähler ist hier eine umständliche Wandlung nötig:
> wüsste nicht warum.
> funktioniert wunderbar mit dem IEEE.NUMERIC_STD
Stimmt.
Vergleiche funktionieren, aber die simple Zuweisung eines Dezimalwerts 
braucht dann diese Umwandlung. Und das:
1
   idx <= to_unsigned(479,idx'length);
ist allemal besser lesbar als:
1
   idx <= "111011111"; -- 479, falls der Kommentar noch stimmt
Aber am schönsten ist immer noch:
1
   idx <= 479;

von erschlagen (Gast)


Lesenswert?

wow ich danke euch, die Diskussion ist für mich sehr fruchtbar gewesen. 
:-)
Bisher jedenfalls, lasst euch gehen; will nichts abwürgen.

von Iulius (Gast)


Lesenswert?

>> Genau dann erkenne ich in der Simulation, wenn der Zähler aus dem
>> definierten Bereich hinausläuft

Durch die Range Angabe beschwöre ich ja gerade den Fall heraus.

"Ach ich geb ja die Range an und damit ist der Counter fertig"

Verwende ich immer und konsistent unsigned, dann bin ich es gewöhnt das 
alles selbst zu bearbeiten und mir entgeht das idr nicht (ist zumindest 
noch nie passiert)



>> aber die simple Zuweisung eines Dezimalwerts braucht dann diese Umwandlung

Hier stimme ich dir zu, wer gerne Dezimalzahlen direkt zuweist, den kann 
das durchaus stören.

Da ich ohnehin in der Hardware nicht in Dezimal rechne nutze ich meist 
x"hex" oder eben direkt binär bei kleinen Zählern.


Da ist eben die Abwägung :  wandle ich lieber hier um oder an einer 
anderen Stelle ?

Wobei man sich fragen muss ob man bei rein Dezimaler/integer Denkweise 
überhaupt noch sinnvoll einzelne Bitpositionen ausgewerten kann.

Wenn ich 479 zuweise kann ich zwar noch sagen das idx(0) = '1' und 
idx(7)='1' (nach umwandlung wohlbemerkt), aber danach hörts langsam auf 
und ich bräuchte einen Taschenrechner.



Deswegen meinte ich ja auch : Geschmackssache. Mir persönlich ist die 
Integer Schreibweise jedenfalls zu weit von der tatsächlichen Hardware 
weg und weil unsigned ohnehin nicht wirklich umständlicher ist nutze ich 
lieber das.

Im Gegenteil, so wie ich arbeite bräuchte ich mit Integer wohl eher mehr 
Umwandlungen.

von erschlagen (Gast)


Lesenswert?

Super. ich muss gestehen daß mir gar nicht recht bewusst war, daß 
unsigned ein Vektor ist. Dadurch erklärt sich schon einiges.
ich habe versucht, daß gelernte bestmöglich umzusetzen. dazu musste das 
Nibble auswählen doch in einen Prozess weichen.

Code ist unten angehängt - 4 Fragen ergeben sich mir aber.
1) ich begreife noch nicht, warum ich im prozess "choose_nibble" nicht 
0,1,2,3 im switch verwenden kann statt der Vektorschreibweise "0000"....
ich hatte es so verstanden, daß ich eben bei unsigned auch numerische 
Vergleiche und Zuweisungen machen darf.
2) Die Synthese spricht von 5.6 ns minumum period. irgendwelche timing 
constraints habe ich nicht zusätzlich angegeben ( so weit bin ich noch 
gar nicht vorgedrungen) Ist das das, was man erwarten könnte, oder habe 
ich schon einen gemeinen Performance killer gemacht? Wer Zeit und Lust 
zur Durchsicht hätte sei herzlich aufgefordert dazu zu posten.
3) Als c Programmierer habe ich mich auf meine Formatierung eingestellt. 
ich habe versucht, das so zu machen, wie ich glaube, daß es in vhdl 
gemacht werden sollte - ich finds dennoch über die Maßen 
unübersichtlich. oder liegt daß nur an mangelnder Erfahrung?
4) unter Implement Design / Place & Route findet sich ein Rufzeichen. 
Scheinbar eine Warnung, aber weder im Warnings Reiter noch sonstwo finde 
ich sie erklärt. :-( Worum handelt es sich, wie brisant ist sie und wie 
vermeidet man sie?

ich danke euch noch einmal recht herzlich!
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity TAKT is
6
   generic(SLOW_CLK : natural := 5);
7
   Port ( clk_in   : in  STD_LOGIC;     
8
          clk_out  : out  STD_LOGIC);  
9
end TAKT;
10
11
architecture Behavioral of TAKT is
12
signal cnt: integer range 0 to 50000000/SLOW_CLK := 0;
13
begin
14
  TAKTGEBER: process (clk_in)
15
  begin
16
      if (clk_in='1' and clk_in'event) then
17
      if( cnt < 50000000/SLOW_CLK) then
18
      cnt <= cnt + 1;
19
      clk_out <= '0';  
20
    else
21
      cnt <= 0;
22
      clk_out <= '1';  
23
    end if;
24
    end if;
25
  end process TAKTGEBER;
26
end Behavioral;
27
28
29
30
library IEEE;
31
use IEEE.STD_LOGIC_1164.ALL;
32
use IEEE.NUMERIC_STD.ALL;
33
34
entity count is
35
  generic(SWAP_CLK : natural := 400);
36
    Port(
37
     segments   : out std_logic_vector(6 downto 0); 
38
     seg_en     : out std_logic_vector(3 downto 0);
39
       clk       : in std_logic);
40
end count;
41
42
architecture Behavioral of count is
43
signal clk_enable : std_logic;
44
signal leds_int   : unsigned(15 downto 0) := (others=>'0');
45
signal swap_cnt   : integer range 0 to 50000000/SWAP_CLK := 0; 
46
signal digit_sel  : unsigned(1 downto 0);
47
signal digit     : unsigned(3 downto 0);
48
49
COMPONENT TAKT
50
  PORT  ( clk_in : in std_logic;
51
          clk_out: out std_logic);
52
end COMPONENT;
53
54
begin
55
  taktausgabe: TAKT
56
    PORT MAP (clk_in=> clk, clk_out=>clk_enable);
57
58
   count: process (clk)
59
   begin
60
    if rising_edge(clk) then
61
      if (clk_enable = '1') then
62
      leds_int <= leds_int + 1;
63
      end if;
64
    end if;
65
  end process count;
66
  
67
  show_segment : process (clk)
68
  begin
69
    if rising_edge(clk) then
70
      case digit is
71
        when "0001" => segments<="1111001";
72
        when "0010" => segments<="0100100";
73
        when "0011" => segments<="0110000";
74
        when "0100" => segments<="0011001";
75
        when "0101" => segments<="0010010";
76
        when "0110" => segments<="0000011";
77
        when "0111" => segments<="1111000";
78
        when "1000" => segments<="0000000";
79
        when "1001" => segments<="0011000";
80
        when "1010" => segments<="0001000";
81
        when "1011" => segments<="0000011";
82
        when "1100" => segments<="1000110";
83
        when "1101" => segments<="0100001";
84
        when "1110" => segments<="0000110";
85
        when "1111" => segments<="0001110";
86
        when others => segments<="1000000";
87
      end case;
88
    end if;
89
  end process show_segment;
90
  
91
  choose_nibble : process (clk) begin
92
    if (clk='1' and clk'event) then
93
      if( swap_cnt < 50000000/SWAP_CLK) then
94
        swap_cnt <= swap_cnt + 1;
95
      else
96
        swap_cnt <= 0;
97
        --digit_sel <= not digit_sel;
98
        digit_sel <= digit_sel + 1;
99
        case digit_sel is
100
          when   "00" => seg_en <= "1110"; digit <= leds_int(3 downto 0);
101
          when   "01" => seg_en <= "1101"; digit <= leds_int(7 downto 4);
102
          when   "10" => seg_en <= "1011"; digit <= leds_int(11 downto 8);
103
          when others => seg_en <= "0111"; digit <= leds_int(15 downto 12);
104
        end case;
105
              
106
      end if;
107
    end if;
108
  end process;
109
         
110
end Behavioral;

von Iulius (Gast)


Lesenswert?

zu 1 :

das klappt bei case nicht da du das "=" verwenden musst um unsigned 
direkt mit einer integer zahl zu vergleichen.

Case und with/select bieten das nicht. Innerhalb eines process ist also 
"if" nötig bzw außerhalb when/else.

Allerdings brauchst du den Mux ohnehin nicht in einem process samt clock 
zu verstecken. Ich würde das so kompakt lösen.
1
seg_en <= x"E" when digit_sel=1 else
2
             x"D" when digit_sel=2 else
3
             x"B" when digit_sel=3 else
4
             x"7";

Das Gleiche gilt übrigens auch für die Case-Anweisung bei dem 
Hex-Lookup.


zu 2 :

5.6ns also 178mhz sind je nach Chip realistisch für das hier verwendete.
Die größte Durchlaufzeit hat dabei mit großer Sicherheit der 
slow_clk-Zähler.

Für solche Counter kann man LFSR nutzen(siehe wikipedia), da der 
absolute Zählerwert unwichtig ist und nur die Periodendauer zählt. Damit 
lässt sich der Maximaltakt ggf noch etwas anheben.
Allerdings wollen wirs für den Anfang mal nicht übertreiben, du kannst 
das problemlos so lassen.

Übrigens aber mal wieder ein Punkt wo integer versagt ;)


zu 3:

Das ist schon so ok. Wenn du mehr übersicht willst dann musst du 
hierarchischer arbeiten, etwa das hex lookup noch als component 
einbinden.

Ansonsten hilft ein guter Quelltext-Editor welcher das Ein-/Ausklappen 
von einzelnen Codeabschnitten unterstützt.


zu 4 :

ohne zu wissen was es ist kann man das nicht sagen. Manche Warnings sind 
eigentlich gar keine, sondern nur Infos, manche sind essentiell und 
weisen auf gravierende Fehler hin.

Leider werden im Laufe des Projekts die Warnings immer weiter zunehmen, 
sodass du am Ende gar nicht mehr die Zeit und Muße haben wirst alle 
durchzusehen.

Besonders wenn man generisch arbeitet und etwa dudurch einzelne 
Bitpositionen wegoptimiert werden können häufen sich die Meldungen sehr 
schnell.

Wenn etwas nicht wie erwartet funktioniert lohnt sich ein Blick allemal, 
ansonsten reicht es wohl gelegentlich mal drauf zu schauen. Für den 
Anfang aber lieber einmal zu oft, denn manchmal finden sich auch 
typische Anfängerfehler (z.b. gated clock) die so schnell aus der Welt 
geschafft werden können.

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


Lesenswert?

> ich habe versucht, daß gelernte bestmöglich umzusetzen.
Das ist gar nicht mal so schlecht gelungen.
Andere brauchen da mehr Iterationen ;-)

> daß ich eben bei unsigned auch numerische Vergleiche und Zuweisungen
> machen darf.
Deshalb verwende ich integer für die Zähler und Indices  ;-)

BTW:
Du könntest auch schreiben:
1
      case digit is
2
        when to_unsigned(1,4) => segments<="1111001";
3
        when to_unsigned(2,4) => segments<="0100100";
4
        when to_unsigned(3,4) => segments<="0110000";
5
        :
Ob das allerdings Leserlicher ist...  :-/

Besser wäre dann eher die Hex-Schreibweise:
1
      case digit is
2
        when x"1" => segments<="1111001";
3
        when x"2" => segments<="0100100";
4
        when x"3" => segments<="0110000";
5
        :
Das geht, weil digit zum Glück 4 Bits hat  ;-)

von erschlagen (Gast)


Lesenswert?

oh, oh, oh.
Vielleicht habe ich die Korken verfrüht knallen lassen. Nachdem die 
Hexadezimale Anzeige mich natürlich nicht zufrieden stellen konnte, habe 
ich nach einer bin-bcd Umwandlung gesucht und bin auf den "shift add 3" 
Algorithmus gestoßen.
Wäre ich zwar niemals selber drauf gekommen, aber leuchtet mir ein. Eine 
Umsetzung habe ich bei obigem Programm natürlich probiert - einige 
std_logic_vector - unsigned Ersetzungen, geschüttelt, sythetisiert.... 
fehlerhaft.

Ich hänge, trotz der riesen Menge, den Code mal an, denn sonst kann man 
mir ja nicht helfen.

Meine Fragen.
1) tja warum zeigen sich eigentlich nicht die erwünschten zahlen von 
0..255?

2) Ich hatte große Hoffnung in die Änderung gesteckt, die das 
einbeziehen des clk in das Modul bin2bcd umfasste. urplötzlich erinnerte 
ich mich an das Mantra bzgl alles takten...

3) Vielleicht der richtige Moment, mit der systematischen fehlersuche 
bzw. Simulation zu beginnen. Wie  wo  was macht man da? Wonach suchen?

4) Im bin2bcd modul habe ich nun unsigned Vektoren verwendet. verstehe 
ich die Zusammenhänge richtig, daß für das Top Modul nur std_logic 
zugelassen ist, weil physikalisch vorhanden, oder ist selbst da unsigned 
zulässig?

Vielleicht sieht jemand den fehler und kann mir die Systematik näher 
bringen

von erschlagen (Gast)


Lesenswert?

1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity TAKT is
6
   generic(SLOW_CLK : natural := 10);
7
   Port ( clk_in   : in  STD_LOGIC;     
8
          clk_out  : out  STD_LOGIC);  
9
end TAKT;
10
11
architecture Behavioral of TAKT is
12
signal cnt: integer range 0 to 50000000/SLOW_CLK := 0;
13
begin
14
  TAKTGEBER: process (clk_in)
15
  begin
16
      if (clk_in='1' and clk_in'event) then
17
      if( cnt < 50000000/SLOW_CLK) then
18
      cnt <= cnt + 1;
19
      clk_out <= '0';  
20
    else
21
      cnt <= 0;
22
      clk_out <= '1';  
23
    end if;
24
    end if;
25
  end process TAKTGEBER;
26
end Behavioral;
27
28
29
library IEEE;
30
use IEEE.STD_LOGIC_1164.ALL;
31
use IEEE.NUMERIC_STD.ALL;
32
33
entity BIN2BCD is
34
  --generic(WIDTH : integer := 8);
35
   Port ( bin  : in  unsigned(7 downto 0);     
36
          bcd  : out unsigned(9 downto 0);
37
       clk  : in  std_logic);  
38
end BIN2BCD;
39
40
architecture behave of BIN2BCD is
41
begin
42
  bcdproc: process(bin)
43
  variable z : unsigned(17 downto 0) := (others=>'0');
44
  begin
45
  if rising_edge(clk) then
46
    z(10 downto 3) := bin;
47
    for i in 0 to 4 loop
48
      z(17 downto 1) := z(16 downto 0);
49
      if z(11 downto 8) > 4 then
50
        z(11 downto 4) := z(11 downto 4) + 3;
51
      end if;
52
      if z(15 downto 12) > 4 then
53
        z(15 downto 12) := z(15 downto 12) + 3;        
54
      end if;
55
    end loop;
56
    bcd <= z(17 downto 8);
57
  end if;
58
  end process bcdproc;
59
end behave;
60
61
62
library IEEE;
63
use IEEE.STD_LOGIC_1164.ALL;
64
use IEEE.NUMERIC_STD.ALL;
65
66
entity count is
67
  generic(SWAP_CLK : natural := 400);
68
    Port(
69
     segments   : out std_logic_vector(6 downto 0); 
70
     seg_en     : out std_logic_vector(3 downto 0);
71
       clk       : in std_logic);
72
end count;
73
74
architecture Behavioral of count is
75
signal clk_enable : std_logic;
76
signal bin_val    : unsigned(7 downto 0);
77
signal bcd_val    : unsigned(9 downto 0);
78
signal digit_sel  : unsigned(1 downto 0);
79
signal digit     : unsigned(3 downto 0);
80
signal swap_cnt   : integer range 0 to 50000000/SWAP_CLK := 0; 
81
82
COMPONENT TAKT
83
  PORT  ( clk_in : in std_logic;
84
          clk_out: out std_logic);
85
end COMPONENT;
86
87
COMPONENT BIN2BCD
88
  Port ( bin  : in  unsigned(7 downto 0);     
89
          bcd  : out unsigned(9 downto 0);
90
       clk  : in std_logic);  
91
end COMPONENT;
92
93
begin
94
  taktausgabe: TAKT
95
    PORT MAP (clk_in=> clk, clk_out=>clk_enable);
96
  umwandlung: BIN2BCD
97
    PORT MAP (bin => bin_val  , bcd=> bcd_val, clk => clk );
98
    
99
  
100
   count: process (clk)
101
   begin
102
    if rising_edge(clk) then
103
      if (clk_enable = '1') then
104
      bin_val <= bin_val + 1;
105
      end if;
106
    end if;
107
  end process count;
108
  
109
  show_segment : process (clk)
110
  begin
111
    if rising_edge(clk) then
112
      case digit is
113
        when "0001" => segments<="1111001";
114
        when "0010" => segments<="0100100";
115
        when "0011" => segments<="0110000";
116
        when "0100" => segments<="0011001";
117
        when "0101" => segments<="0010010";
118
        when "0110" => segments<="0000011";
119
        when "0111" => segments<="1111000";
120
        when "1000" => segments<="0000000";
121
        when "1001" => segments<="0011000";
122
        when "1010" => segments<="0001000";
123
        when "1011" => segments<="0000011";
124
        when "1100" => segments<="1000110";
125
        when "1101" => segments<="0100001";
126
        when "1110" => segments<="0000110";
127
        when "1111" => segments<="0001110";
128
        when others => segments<="1000000";
129
      end case;
130
    end if;
131
  end process show_segment;
132
  
133
  choose_nibble : process (clk) begin
134
    if (clk='1' and clk'event) then
135
      if( swap_cnt < 50000000/SWAP_CLK) then
136
        swap_cnt <= swap_cnt + 1;
137
      else
138
        swap_cnt <= 0;
139
        digit_sel <= digit_sel + 1;
140
        case digit_sel is
141
          when   "00" => seg_en <= "1110"; digit <= bcd_val(3 downto 0);
142
          when   "01" => seg_en <= "1101"; digit <= bcd_val(7 downto 4);
143
          when others => seg_en <= "1011"; digit <= "00"&bcd_val(9 downto 8);
144
        end case;
145
              
146
      end if;
147
    end if;
148
  end process;
149
         
150
end Behavioral;

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


Lesenswert?

> habe ich nach einer bin-bcd Umwandlung gesucht und bin auf den
> "shift add 3" Algorithmus gestoßen.
Woher hast du die Idee?
Ist das dein eigener VHDL-Quellcode?

> architecture behave of BIN2BCD is
Du weißt schon, was eine for-Schleife in VHDL macht?
Damit wird einfach nur Hardware mehrfach erzeugt...
Wolltest du das?

Ich mach das immer so:
http://www.lothar-miller.de/s9y/categories/44-BCD-Umwandlung
Auch da ist die gleiche Idee dahinter: wenn Übertrag, dann +3

von erschlagen (Gast)


Lesenswert?

Die Idee über for Schleife ist natürlich nicht von mir. Mit einer 
Umsetzung von Null an würde ich mich auch selber noch zu sehr unter 
Druck setzen. habe ich umgewandelt. z.B. unter Benutzung der unsigned 
Vektoren.
Die Verwendung der For Schleife verstehe ich so, daß diese quasi 
entflochten wird und somit für kleine Tiefen einen Vorteil gegenüber 
einer Statemaschine wie bei dir hat, die ja immer mehrere Taktzyklen 
dauern muss. Ich werde mir beide Lösungen mal genauer anschauen und 
darüber nachdenken.
Für die Umwandlung von Zahlen, die sich alle zig Takte ändern wäre ja 
eine Routine, die paar Takte dauert irrelevant. Wenn ich mit den bcd 
Werten eines  schnellen Datenstroms etwas machen müsste, würde bei 
deiner Lösung dessen Rate durch die notwendigen Takte pro Umwandlung 
bestimmt?
Vermutlich denke ich einfach noch zu kompliziert bzw. will zu viel auf 
einmal beachten.

Würdest du denn sagen bei mir wird Murks angezeigt (also unsinnige bcd 
Zahlen incl. As..Fs) wegen eines Fehlers in der Routine oder ist das 
Problem eher in der Verschaltung der bin2bcd im count zu suchen.
Ich versuche bewusst components und auch Prozesse die keine sein müssten 
s.o. zu verwenden, um ein Gefühl dafür zu bekommen.
Aufteilung auf Sourcen und anlegen eines component pools kann ja später 
erfolgen.

Erst mal sollte ds Programm funktionieren finde ich :-(

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


Lesenswert?

> Würdest du denn sagen bei mir wird Murks angezeigt (also unsinnige bcd
> Zahlen incl. As..Fs) wegen eines Fehlers in der Routine oder ist das
> Problem eher in der Verschaltung der bin2bcd im count zu suchen.
>> Vielleicht der richtige Moment, mit der systematischen fehlersuche
>> bzw. Simulation zu beginnen.
Es ist nie zu spät, aber ich hätte schon früher damit angefangen...  ;-)

> Wie  wo  was macht man da? Wonach suchen?
Am einfachsten testest du jedes einzelne deiner Untermodule, und wenn du 
Lust und Zeit hast, das Top-Modul zusammen mit den Untermodulen auch 
noch...

von erschlagen (Gast)


Lesenswert?

Das gibt mir zwar jetzt keinen wirklich konkreten Anhaltspunkt wie und 
wo ich den Hebel ansetze :-(, aber ich werd in den nächsten Tagen noch 
mal darüber brüten und ggf. konkreter fragen.
Informationen über Projektplanung und Testbenches sind rar gesäht. 
Deinen Buchtip habe ich allerdings bestellt.

Was mich jetzt aber mehr und mehr interessiert sind Vor- und Nachteile 
der For Schleife.

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.