Hallo, ich habe für einen Cyclone5 einen variablen Clockdivider geschrieben, der leider nur bei statischer Vorgabe funktioniert. Die Idee ist, ich habe einen Divider den ich über eine extern anlegbares Bitmuster steuern kann. Als Anhang habe ich die zwei verwendeten Dateien. Das Ganze funktioniert, sobald ich in fpgatest.v:15 eine feste Zahl anstatt der Speicherzelle vorgebe, was allerdings nicht Sinn und Zweck der Sache ist. Der Crux ist dass es in der Simulation funktioniert. Wenn ich es aber auf den FPGA spiele bekommt der Divider immer 0 als Divisionswert. Hat jemand eine Idee was ich da falsch mache?
Stefan A. schrieb: > Die Idee ist, ich habe einen Divider den ich über eine extern anlegbares > Bitmuster steuern kann. Ok. Was willst Du mit dem resultierenden Takt anstellen? Duke
Hm, Du deklarierst ein Register, das initial den Wert 2000 bekommt und sonst nicht mehr verändert wird. Sprich, es ist eigentlich kein Register. Das sollte zumindest eine Warning geben. Woher weißt Du, dass divider immer 0 bleibt? Pack das Register mal in ein sequential statement und schreib in jedem Takt 2000 hinein.
Das Ganze ist aus einem größeren Projekt, das einen konfigurierbaren UART mit CRC hat. Dort kann man über ein Dual Port RAM vom Prozessor aus Transferlänge und Clock einstellen. Ich bin sicher, dass dort 0 steht, weil ohne das "if(divider == 0" kein takt mehr kommt weil "if(divider /2 -1) -> 0/2 -1 = 0xFFFF und der SignalTap Logic Analyzer von Quartus sagt das Gleiche.
Die Idee mit jeden Takt was reinschreiben war nicht schlecht. Ich habe folgendes hinzugefügt:
1 | always @ (posedge FPGA_CLK1_50) |
2 | begin |
3 | if(divider == 0) |
4 | divider <= 1000; |
5 | end |
Und siehe da, ein Takt am Ausgang. Allerdings nicht der für divider <= 1000, sondern divider <= 2000, wie bei initial. Gibt es da Optimizer, die Amok laufen können?
Stefan A. schrieb: > clock_out <= ~clock_out; > Hat jemand eine Idee was ich da falsch mache? Du erzeugst Takte, wo du mit Clock-Enables arbeiten müsstest. Das ist aber ein eher generelles Problem... Stefan A. schrieb: > Das Ganze ist aus einem größeren Projekt, das einen konfigurierbaren > UART mit CRC hat. Dort kann man über ein Dual Port RAM vom Prozessor aus > Transferlänge und Clock einstellen. Dann musst du diesen Teil mit dem DPRAM auch noch implementieren. Durch das Weglassen dieses Interfaces beobachtest du hier ein simples "Wegoptimieren": weil du das Register divider nie verwendest (in Form von "verändern"), wird es hinfortoptimiert. Du solltest den Synthesizer zwingen, indem du z.B. einen Reset für divider einführt. Und bei deren Abwesenheit den Wert zuweist. EDIT: schon gesehen, du hast es jetzt so gemacht... ;-) Stefan A. schrieb: > Gibt es da Optimizer, die Amok laufen können? Das steht im Handbuch der Toolchain. Und ja, das ist ein Optimierungseffekt.
:
Bearbeitet durch Moderator
Ok ich konnte das in meinen großen Programm jetzt nachvollziehen. Mit volgendem Code funktioniert es:
1 | if(divider < 4) |
2 | begin |
3 | divider <= 1000; |
4 | end |
Allerdings in meinem Fall seltsam, da es auch ohne nicht wegoptimiert werden dürfte. Ich habe kurz danach nämlich seit jeher folgendes Konstrukt:
1 | control_verarbeiten <= control_verarbeiten +1; |
2 | case(control_verarbeiten) |
3 | ... |
4 | ... |
5 | // Lowbyte von Divider liegt an |
6 | 7: begin |
7 | divider[7:0] <= mem_control_readdata; |
8 | mem_control_address <= 0; |
9 | end |
10 | // Highbyte von Divider liegt an |
11 | 8: begin |
12 | divider[15:8] <= mem_control_readdata; |
13 | end |
Der Witz ist, das hat auch schon einmal funktioniert. Erst seit ich die CRC Funktion dazugebastelt habe klappt es nichtmehr. In der Simulation allerdings kein Problem. Meiner Ansicht nach ein klarer Bug, wundert mich allerdings nicht so wirklich. Das Quartus ist allgemein sehr hakelig und stürzt auch regelmäßig ab.
initial Blocks sind im Allgemeinen nicht synthesierbar. (@VHDLer, das entspricht einem Process der nur einmal durchlaufen wird) statt
1 | reg [15:0] divider; |
2 | initial divider = 2000; |
1 | reg [15:0] divider = 0; |
(Verilog 2001, sollten alle aktuellen FPGA Tools inzwischen können)
So, ich hab es gerade nochmal getestet. Es gibt 2 Konstallationen die funktionieren: 1. Trivial
1 | reg [15:0] divider = 2000; |
2. Kurios
1 | reg [15:0] divider; |
2 | initial divider = 2000; |
3 | |
4 | always @ (posedge FPGA_CLK1_50) |
5 | begin |
6 | if(divider == 0) |
7 | divider <= 0; |
8 | end |
Da wie in Version 2 ersichtlich die "initial" Anweisung offensichtlich ausgewertet wird (Takt wird tatsächlich durch 2000 geteilt) und das if an sich nutzlos ist, ist das meiner Auffassung nach ein Bug. Besten Dank an Alle.
Stefan A. schrieb: > Da wie in Version 2 ersichtlich die "initial" Anweisung offensichtlich > ausgewertet wird (Takt wird tatsächlich durch 2000 geteilt) und das if > an sich nutzlos ist, ist das meiner Auffassung nach ein Bug. Nö, weil Links die Zeit nach dem Takt und rechts die Zeit vor dem Takt. Du verschleppst damit bei einem Zähler einen Takt und ob das hier richtig ist, wage Ich mal zu bezweiffeln. Du muss mit einem Takt Vorlauf denken, also: "Wenn Zähler + Inkrement im nächsten Takt mehr als Limit, dann limit or wrap etc..."
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.