Forum: FPGA, VHDL & Co. Erste Gehversuche Verilog


von T. F. (sar)


Lesenswert?

Hi,

Ich probiere gerade folgendes in Verilog auf einem Lattice FPGA zu 
realisieren.

Ich habe einen Eingang, sync_in, und wenn dieser von high auf low 
wechselt, möchte ich einen Zähler starten. Der Zähler soll dann weiter 
inkrementieren bis er einen maximalen Wert erreicht. Dann soll der 
Zähler auf 0 zurück gesetzt werden und bis auf die nächste fallende 
Flanke warten.

Ich habe bis jetzt mit VHDL zu tun gehabt und probiere in einem anderen 
Projekt eine kleine Änderung durchzuführen: Der Zähler zuvor rannte 
einfach von 0 auf max und fing dann wieder bei 0 an.

Mit folgendem Konstrukt erhalte ich fast das gewünschte Verhalten, 
allerdings scheint cnt zwischen Wert 0 und StopValue-1 hin und her zu 
wackeln, wenn keine Flanke von sync_in kommt. Ich komme mit Lattice 
Diamond irgendwie noch nicht klar und bekomme keine Simulation dafür 
hin. Gepaart mit meinem Verilog Verständnis komme ich derzeit nicht 
weiter.

Hier der Code:
1
wire      reset_sw_n;
2
reg        sync_in_r, sync_in_r1;
3
reg        start_load;
4
reg  [12:0]    cnt;
5
6
// synchronize sync signal
7
always @(posedge clk)
8
begin
9
  sync_in_r <= sync_in;
10
end
11
12
always @(posedge clk)
13
begin
14
  sync_in_r1 <= sync_in_r;
15
end
16
17
// the counter
18
always  @(posedge clk or negedge reset_sw_n)
19
begin
20
  // reset count value and start_load
21
  if(~reset_sw_n)
22
  begin
23
    cnt  <= #1 13'd0;  
24
    start_load <= 1'b0;
25
  end
26
  // if sync_in_r1 = low and sync_in_r = 1 we have a falling edge, set start_load = 1
27
  else if(sync_in_r1 == 1'b0)
28
    if (sync_in_r == 1'b1)
29
      start_load <= #1 1'b1;
30
  // if start_load = 1, increase counter. When StopValue is reached set start_load = 0 and count value to zero
31
  else if (start_load == 1'b1)
32
    begin
33
    if (cnt == StopValue)
34
      begin        
35
        start_load <= 1'b0;
36
        cnt  <= #1 13'd0;
37
      end
38
    else
39
      cnt  <= #1 cnt + 1'b1;
40
    end  
41
end

Hoffe ihr könnt mir weiter helfen.

Danke

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


Lesenswert?

Ich kann zwar auch kein Verilog aber wenn diese #1 symbolische 
Verzögerungen in einer Verhaltensbeschreibung sind, dann lass die mal 
weg...

: Bearbeitet durch Moderator
von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Ich kannte diese Formulierung mit # nicht, im verlinkten Wikiartikel 
steht dazu:
"Vielleicht ist es ganz sinnvoll, an dieser Stelle nochmal zu erwähnen, 
dass das Verzögerungszeichen nicht synthetisierbar ist."
Verzögerungen muss man schon explizit erstellen, einen Zähler und dann 
die Verknüpfung damit.

: Bearbeitet durch User
von Cle (Gast)


Lesenswert?

Christoph K. schrieb:
> Ich kannte diese Formulierung mit # nicht, im verlinkten
> Wikiartikel
> steht dazu:
> "Vielleicht ist es ganz sinnvoll, an dieser Stelle nochmal zu erwähnen,
> dass das Verzögerungszeichen nicht synthetisierbar ist."
> Verzögerungen muss man schon explizit erstellen, einen Zähler und dann
> die Verknüpfung damit.

Ohne zu wissen was sich der TO gedacht hat, ich kenne die Pounddelays 
für die Simulation. Bei der Sythese werden diese dann ignoriert, muss 
daher kein Problem sein. Das verzögert das Signal in der Simulation nur 
um einen Tick.

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


Lesenswert?

Cle schrieb:
> Das verzögert das Signal in der Simulation nur um einen Tick.
Eben das kann in der Simulation diesen seltsamen Effekt auslösen. Was 
ist denn in der Verilog Simulation die kürzeste Verzögerung? Und was ist 
der Simulationstakt? Hängen die irgendwie zusammen?

Kurz: in eine Verhaltensbeschreibung kommt keine Verzögerung.

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


Lesenswert?

T. F. schrieb:
> Ich komme mit Lattice Diamond irgendwie noch nicht klar und bekomme
> keine Simulation dafür hin.
Also doch keine Simulation...
Zum Simulieren verwendest du bei Lattice den Aldec Simulator. Der ist 
eigenständig und du musst damit ein eigenes Simulationsprojekt 
aufsetzen, das im Idealfall einfach die selben Sourcedateien wie Diamond 
verwendet und denen eine Testbench hinzufügt.

von bko (Gast)


Angehängte Dateien:

Lesenswert?

habe mal ein paar mehr begin-end Paare eingebaut, nun tut der code etwas 
anderes, wenn zweimal hindereinander "if" dann weiß ich nicht zu welchem 
der "if"s das "else" dann gehört ... (aber so richtig 100% kann ich 
verilog auch nicht!)

Simulieren kann man auch mit "http://iverilog.icarus.com/"; + ansehen mit 
http://gtkwave.sourceforge.net/
1
        
2
`default_nettype none
3
4
module testcnt(input clk, input sync_in,input reset_sw_n,
5
                      input [12:0] StopValue);
6
7
wire      reset_sw_n;
8
reg        sync_in_r, sync_in_r1;
9
reg        start_load;
10
reg  [12:0]    cnt = 0;
11
12
// synchronize sync signal
13
always @(posedge clk)
14
begin
15
  sync_in_r <= sync_in;
16
end
17
18
always @(posedge clk)
19
begin
20
  sync_in_r1 <= sync_in_r;
21
end
22
23
// the counter
24
always  @(posedge clk or negedge reset_sw_n)
25
begin
26
  // reset count value and start_load
27
  if(~reset_sw_n)
28
    begin
29
    cnt  <= #1 13'd0;  
30
    start_load <= 1'b0;
31
    end
32
  // if sync_in_r1 = low and sync_in_r = 1 we have a falling edge, set start_load = 1
33
  else
34
     begin 
35
     if(sync_in_r1 == 1'b0)
36
        begin
37
        if (sync_in_r == 1'b1)
38
          start_load <= #1 1'b1;
39
        end
40
     // if start_load = 1, increase counter. When StopValue is reached set start_load = 0 and count value to zero
41
     else 
42
     begin
43
     if (start_load == 1'b1)
44
        begin
45
           if (cnt == StopValue)
46
             begin        
47
               start_load <= 1'b0;
48
               cnt  <= #1 13'd0;
49
             end
50
              else
51
                cnt  <= #1 cnt + 1'b1;
52
           end 
53
        end
54
     end  
55
end
56
57
endmodule

von Frank S. (schroederde)


Lesenswert?

1
`timescale 1ns / 1ns
2
3
module TiefpassTrigger
4
(
5
clkin,
6
startsig,
7
maxcount
8
);
9
10
input clkin;
11
input startsig;
12
input [15:0]maxcount;   
13
14
reg state[1:0] = 0;
15
reg laststartsig = 0; 
16
reg[15:0]count = 0;
17
always@(posedge clkin)
18
  begin          
19
    laststartsig <= startsig;  
20
    case(state)
21
      0:
22
        begin 
23
          count <= 0;
24
          if ((startsig == 0) && (laststartsig == 1))
25
            begin
26
              count <= count + 1;
27
              state <= 1;
28
            end
29
        end
30
      1:
31
        begin  
32
          count <= count + 1;
33
          if(count >= maxcount)
34
            state <= 2;
35
        end         
36
      2:
37
        begin  
38
          if ((startsig == 0) && (laststartsig == 1))
39
            begin
40
              state <= 0;
41
            end
42
        end
43
    endcase
44
  end

: Bearbeitet durch Moderator
von Frank S. (schroederde)


Lesenswert?

Hmm. Funzt [verilog]?

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


Lesenswert?

Frank S. schrieb:
> Hmm. Funzt [verilog]?
Nein. Nimm [c] oder [code]

von T. F. (sar)


Lesenswert?

Hi,

Vielen Dank für die Kommentare. Teile des Codes stammen aus dem Projekt, 
welches ich mit dieser Triggerung / Synchronisierung erweitern will. 
Habe von dort die # Geschichten übernommen.

Danke Frank für deinen Code. Habe jetzt in der Zwischenzeit Xilinx ISE 
wieder hochgefahren und verwende dieses zum Simulieren. Damit habe ich 
schon gearbeitet.

@Frank: Wieso bist du den Weg über eine State-Maschine gegangen?

Folgendes erzeugt unter Xilinx ISE das gewünschte Verhalten:
1
`timescale 1ns / 1ns
2
3
module test(
4
    input clk,
5
    input sync,
6
    input rst
7
    );
8
9
10
reg      reset_sw_n;
11
reg      sync_r;
12
reg [12:0]  cnt;
13
reg       enable;
14
15
16
always @(posedge clk)
17
begin
18
  reset_sw_n <= ~rst;
19
end
20
21
22
always @(posedge clk) begin
23
  sync_r <= sync;
24
  
25
  if (reset_sw_n) begin
26
    cnt <= 13'b0 ;
27
    enable <= 0;
28
  end else if ((sync_r == 1) && (sync == 0) && (enable== 0)) begin
29
    enable <= 1;
30
  end else if (enable) begin
31
    if (cnt == 13'd16) begin
32
      cnt <= 0;
33
      enable <= 0;
34
    end else begin
35
      cnt <= cnt + 1;
36
    end
37
    
38
  end
39
end
40
41
endmodule

Werde das jetzt mal auf der Hardware ausprobieren.

Danke an alle

von Vancouver (Gast)


Lesenswert?

Wo genau das Problem liegt, sehe ich Moment auch nicht (Ich bin 
System-Verilog Novize), aber einen Fehler sehe ich: Du testest auf 
sync_in_r1==0 und sync_in_r==1, damit hast Du aber eine steigende und 
keine fallende Flanke (weil sync_in_r1 der ältere Wert ist).

Weiterhin könntest Du
1
  else if(sync_in_r1 == 1'b0)
2
    if (sync_in_r == 1'b1)

vereinfachen zu
1
  else if(sync_in_r1 == 1'b0 && sync_in_r == 1'b1)

und die ersten beiden always-statements mergen. Das alles löst nicht das 
Problem, aber der Code wird übersichtlicher, vllt findest Du dann 
heraus, was schiefläuft. Hat cnt die gleiche Breite wie StopValue? 
Verilog macht da manchmal seltsame Sachen ohne Vorwarnung. Ja, und lass 
die Timing-Statements erst mal raus. Es geht jetzt nur um die funtionale 
Simulation

von T. F. (sar)


Lesenswert?

Hi,

Mit obigem Code funktionierts jetzt.

Danke nochmals.

von Frank S. (schroederde)


Lesenswert?

Hi

T. F. schrieb:
> @Frank: Wieso bist du den Weg über eine State-Maschine gegangen?

Weil Deine Aufgabenbeschreibung nach einer State-Machine geschriehen hat 
;)

T. F. schrieb:
> Ich habe einen Eingang, sync_in, und wenn dieser von high auf low
> wechselt, möchte ich einen Zähler starten.

entpricht:
1
        //state 0
2
        if ((startsig == 0) && (laststartsig == 1))
3
            begin
4
              count <= count + 1;
5
              state <= 1;
6
            end

T. F. schrieb:
> Der Zähler soll dann weiter
> inkrementieren bis er einen maximalen Wert erreicht.
1
         //state 1
2
         if(count >= maxcount)
3
            state <= 2;

T. F. schrieb:
> Dann soll der
> Zähler auf 0 zurück gesetzt werden und bis auf die nächste fallende
> Flanke warten.

Oh hier war ein Fehler:
1
          // state 2
2
          count <= 0; //Hatte ich vergessen
3
          if ((startsig == 0) && (laststartsig == 1))
4
            begin
5
              state <= 0; //Wenn er sofort wieder zu zählen beginnen soll
6
                          //state <= 1;
7
            end

...Ausserdem finde ich eine Statemachine deutlich übersichtlicher als 
die ganzen verschachtelten ifs.

: Bearbeitet durch User
von Lattice User (Gast)


Lesenswert?

T. F. schrieb:
>
> Mit obigem Code funktionierts jetzt.
>

Allerdings fehlt diesem das korrekte Einsynchroniseren des externen 
Syncsignals. In der orginalen Version war das noch vorhanden. Ohne wird 
es ab und zu auf der Hardware Fehler geben. Die Statemachine Version von 
Frank kann sogar in einen illegalen Zustand springen.

von Frank S. (schroederde)


Lesenswert?

Naja, wenn schon Erbsen zählen, dann aber richtig.

Lattice User schrieb:
> Die Statemachine Version von
> Frank kann sogar in einen illegalen Zustand springen.

Was aber völlig gleichgültig ist. Das Modul hat keine Ausgänge.

Dieses Snippet sollte keine vollständige Lösung darstellen, sondern 
einen Weg aufzeigen.

: Bearbeitet durch User
von T. F. (sar)


Lesenswert?

@Lattice User:

Ja das war in dieser Version noch nicht drinnen, habe ich dann aber nach 
den ersten Tests wieder eingebaut.

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.