Hallo,
ich habe mehrere (VHDL-)Module über Multiplexer an den Picoblaze
gehängt. Der Multiplexer wird über die Adresse/Port_ID gesteuert und WS,
bzw. RS zusammen mit der Abfrage der Adresse ergibt ein Read-Enable für
das jeweilige Modul.
Soweit so gut - nur ich bekomme die Daten nicht in einem Taktzyklus in
den Pico. Soweit ich es verstanden habe, kann die steigende
Strobe-Flanke verwendet werden, um den Multiplexer zu schalten (da zu
dem Zeitpunkt die Adresse anliegt), bei der fallenden Strobe-Flanke
liest der Pico dann die Daten ein.
In der Simulation liegen die Daten, die ich lesen will genau einen
Systemtakt-Zyklus später an.
Gibt es irgendwelche intelligenteren Tricks, außer die gleiche Adresse
2mal auszulesen? Kommt mir irgendwie doof vor, aber ich bin auf keine
bessere Idee gekommen.
Module, die auf beide Taktflanken reagieren soll man ja nur im äußersten
Notfall verwenden (ist ja auch an IO-FFs gekoppelt).
an den Multiplexer gehört nur port_id und NICHT write strobe.
jeder Eingang des Mux braucht ein eigenes FF.
in diesem FF kannst dann deinen zustand Speichern.
Hinter dem Mux folgt dann noch ein weiteres FF, und dann passt das
Timing wieder, schau mal in die Picoplace Anleitung, da ist auch ein
Beispiel.
> Der Multiplexer wird über die Adresse/Port_ID gesteuert und WS,> bzw. RS zusammen mit der Abfrage der Adresse ergibt ein Read-Enable für> das jeweilige Modul.
Wenn Du den Satz genau liest, steht dort, dass der Multiplexer nur über
die Port_ID gesteuert wird. Die Kombinatorik, die aus Adresse und RS ein
Read-enable macht, steht an anderer Stelle.
Wenn ich die RTL-Ausgabe von meinem Code mit dem Picoblaze-Beispiel
vergleiche, dann passt das schon.
Was nicht passt, ist das Timing - aber mir scheint, dass Du meine Frage,
bzw. mein Problem an der Stelle nicht verstanden hast.
Dank Dir trotzdem für Deine Aufmerksamkeit.
Beiliegendes Bild aus dem Picoblaze-Handbuch verdeutlicht mein
"Problem":
Die Inport-Daten liegen versetzt zum Systemtakt des Picoblaze an.
Wenn das Modul, welches die Daten bereitstellen soll, mit dem gleichen
Systemtakt läuft, wie der Picoblaze und dieses den Readstrobe auswertet,
stehen die Daten erst dann bereit, wenn der Picoblaze gelesen hat.
Also müsste ich 2mal lesen oder den Picoblaze mit halbem Systemtakt
laufen lassen. Oder gäbe es noch eine intelligentere Lösung?
Das Konzept mit dem Read Strobe irgendwo Daten Abzuholen ist verkehrt.
Schieb deine Daten in ein FF, und aus diesem FF liest dann der
Picoblaze.
Dieses FF liegt am Systemtakt, und ist somit immer Aktuell.
Das oben erwähnte Beispiel hab ich nun mal angehängt.
Vielleicht wird dir das mit ein wenig VHDL Code Klarer:
1
process(port_id,i0,i1,i2)
2
begin
3
caseport_idis
4
whenx"00"=>in_port_i<=i0;-- port 0
5
whenx"01"=>in_port_i<=i1;-- port 1
6
whenx"02"=>in_port_i<=i2;-- port 2
7
whenothers=>in_port_i<=(others=>'-');
8
endcase;
9
endprocess;
10
11
process(clk)begin--in_port pipeline
12
ifrising_edge(clk)andread_strobe='0'then
13
in_port<=in_port_i;
14
endif;
15
endprocess;
hier werden 3 Ports für den Picoblace gemultiplext
> Das Konzept mit dem Read Strobe irgendwo Daten Abzuholen ist verkehrt.
Du bist mir vielleicht ein lustiger Vogel. Was gibt es denn für
Alternativen?
> Schieb deine Daten in ein FF, und aus diesem FF liest dann der> Picoblaze.
Und woher soll ein Modul wissen, dass es jetzt Daten in das FF schieben
kann/soll/darf?
> Vielleicht wird dir das mit ein wenig VHDL Code Klarer:
1
ifrising_edge(clk)andread_strobe='0'then
Also mit der Bedingung ist Dir Datenverlust völlig egal?!?
Denn immer wenn der Picoblaze nicht liest, ist read_strobe 0
Falls Du die fallende Flanke von read_strobe erfassen willst, geht das
so nicht und wenn Du es dann richtig auscodiert hast, bist Du auf dem
gleichen Stand wie ich, dass die Daten erst dann zur Verfügung stehen,
wenn der Picoblaze bereits gelesen hat :)
Wolltest Du mir mit dem Beispiel zeigen, dass Du noch nix mit dem
Picoblaze gemacht hast, oder was sollte das werden?
Anfänger schrieb:
>> Das Konzept mit dem Read Strobe irgendwo Daten Abzuholen ist verkehrt.>> Du bist mir vielleicht ein lustiger Vogel. Was gibt es denn für> Alternativen?
Immer schön freundlich bleiben...
> Und woher soll ein Modul wissen, dass es jetzt Daten in das FF schieben> kann/soll/darf?
Dürfen: Immer
Wann: Möglichst Taktsyncron
Soll: Siehe unten
> gleichen Stand wie ich, dass die Daten erst dann zur Verfügung stehen,> wenn der Picoblaze bereits gelesen hat :)
- Die gültigen Daten liegen am Ausgang deiner Komponente immer an
- In dem Momment wo der PicoBlaze die Daten übernommen hat legt er Read
Strobe auf 1
- Im darauffolgenden Takt weiß deine Komponente: Aha die Daten wurde
abgeholt ich soll /kann/darf jezt neue Daten an den Ausgang legen z.B.
so:
1
ifrising_edge(clk)then
2
ifread_strobe='1'then
3
output_port<=meine_neuen_daten;
4
endif;
5
endif;
> Also mit der Bedingung ist Dir Datenverlust völlig egal
Es gibt auch Komponenten die halt keinen inneren Zustand haben (z.B. ein
paar Taster an nem I/O Pin) wo halt einfach IMMER die aktuellen Daten
anliegen und eben der Readstrobe egal ist.
Den BRaucht man nur wenn es einen "nächsten Datensatz" gibt wie z.B. bei
einem FIFO o.ä. (wird z.B. bei dem FIFO der PicoBlaze UART so gemacht).
Der ReadStrobe sagt dir aber immer: Die Daten wurden gelesen nicht: leg
die Daten zum lesen an!
> Wolltest Du mir mit dem Beispiel zeigen, dass Du noch nix mit dem> Picoblaze gemacht hast, oder was sollte das werden?
Der Code war aus einem Projekt, das ich etwa vor einem Jahr gemacht
habe, und da funktioniert er einwandfrei
>
1
ifrising_edge(clk)andread_strobe='0'then
>> Also mit der Bedingung ist Dir Datenverlust völlig egal?!?
Es passiert genau das, was passieren soll, der Picoblaze bekommt 2 Takte
nach einem Lesebefehl den Inhalt des FF
> Und woher soll ein Modul wissen, dass es jetzt Daten in das FF schieben> kann/soll/darf?
Da zitier ich mich mal selbst:
>Dieses FF liegt am Systemtakt, und ist somit immer Aktuell.
Das klappt natürlich nur, wenn du mit jedem Takt aktuelle Daten in das
FF Schreibst.
>Du bist mir vielleicht ein lustiger Vogel
Bitte, gerne geschehen
>>> Das Konzept mit dem Read Strobe irgendwo Daten Abzuholen ist verkehrt.>> Du bist mir vielleicht ein lustiger Vogel...> Immer schön freundlich bleiben...
Das sollte keinesfalls unfreundlich sein! Ich wollte nur meiner
Verwunderung Ausdruck verleihen - so ganz ohne wenn und aber, ohne
Nachfrage - empfand ich den Satz als ganz schön arrogant.
Ihr habt mir jetzt beide den "Trivial"-Fall beschrieben, bei dem die
Daten ständig zur Verfügung stehen. Aber nicht alles im Leben läßt sich
auf 1. Klasse Lektion 1 Niveau runterdrücken ;)
Was mache ich, wenn ich ein Modul habe, welches z.B. einen Status und
mehrere Daten unterschiedlicher Breite hat?
> Der ReadStrobe sagt dir aber immer: Die Daten wurden gelesen nicht: leg> die Daten zum lesen an!
Das war mir schon klar. Ich fand nur nix besseres, um den Befehl nach
außen zu geben, doch bitte die Daten anzulegen.
Ich war es so angegangen, dass ich über die Adresse bestimme, welcher
Wert gelesen werden soll. Wenn ich ein Modul vom Picoblaze aus lesen
und beschreiben will, reicht die Adresse alleine ja nicht aus, um die
Daten bereitzustellen. Deshalb hatte ich die Adresse kombiniert mit RS,
bzw. WS zu einem readenable bzw. writeenable. Ja und irgendwo dazwischen
liegt dann auch noch der Multiplexer.
Aber da alle Befehle bei Picoblaze ja 2 Takte dauern, ist es wohl egal,
ob ich 2mal lese oder irgendwas anderes vorher mach, um einen Lesezyklus
einzuleiten.
Insofern "Danke schön" für die Diskussion und nix für ungut!
Anfänger schrieb:
> Nachfrage - empfand ich den Satz als ganz schön arrogant.
Dan solltest du lockerer werden... das Leben ist nur so schwer wie man
es nimmt, und nicht jeder hat Lust seine Forenbeiträge erst 5x gegelesen
zu lassen ob man sie nicht vieleicht falsch verstehen könnte ;)
> Daten ständig zur Verfügung stehen. Aber nicht alles im Leben läßt sich> auf 1. Klasse Lektion 1 Niveau runterdrücken ;)
Und nicht alles läßt sich durch die Weltformel ausdrücken.. es kommt
halt immer auf den konkreten Anwendungsfall an.
> Was mache ich, wenn ich ein Modul habe, welches z.B. einen Status und> mehrere Daten unterschiedlicher Breite hat?
Ganz simpel: Unterschiedliche Addressen... auf einer liegt der Status,
auf einer zweiten die Adresse und auf einer dritten das Datenregister...
> Ich war es so angegangen, dass ich über die Adresse bestimme, welcher> Wert gelesen werden soll. Wenn ich ein Modul vom Picoblaze aus lesen> und beschreiben will, reicht die Adresse alleine ja nicht aus, um die> Daten bereitzustellen. Deshalb hatte ich die Adresse kombiniert mit RS,
Warum nicht? Stell dir das ganze doch einfach wie ein RAM vor: Du kannst
eine Adresse 1000x lesen das ist egal, es liegen einfach IMMER die Daten
für die aktuelle Adesse an, ob man sie dan wirklich konkret einliest ist
egal. Nur beim Schreiben braucht man definitiv ein Write Strobe...
Der Readstrobe sit wie gesagt nur für Module die bspw. über einen Fifo
Daten austauschen und somit wissen müssen wann ein Datum gelesen wurde
(hier nochmal der Hinweis auf die UART vom PicoBlaze...)
> Insofern "Danke schön" für die Diskussion und nix für ungut!
Bitteschön...
Hallo,
zuerst einmal möchte ich Abbitte bei Michael Sauron leisten.
Der Punkt ist, dass ich erst jetzt verstanden habe, dass er mir ja in
dem "kritisierten" Beitrag gezeigt hat, wie man es macht.
Der Knackpunkt war der, dass ich 2 geschachtelte Multiplexer habe und
dass der Trick eben bedeutet, dass man die Daten ungetacktet zum FF
schiebt. Das war mir seinerzeit nicht am Beispiel aufgegangen.
Ich habe es jetzt so gelöst, in dem ich die Ausgangsdaten außerhalb
eines Prozesses setze:
Somit liegen die zu lesenden Daten am Ausgang an, sobald die Adresse
geschaltet wird. Da Lese- und Schreibadresse der gleiche Bus ist,
verändern sich die Lesedaten auch wenn eine andere Adresse beschrieben
werden soll. Da an dem 8Bit-Bus aber nur der Pico hängt, kann ich damit
leben ;)
Das getaktete FF liegt dann im Multiplexer, der die unterschiedlichen
Module verbindet.
>> Nachfrage - empfand ich den Satz als ganz schön arrogant.> Dan solltest du lockerer werden...
Yepp - da hast Du völlig Recht. Da ich seine Ausführungen nicht
verstanden hatte, habe ich nicht gesehen, dass mir sein Beitrag helfen
könnte. Somit war es (für mich) eine Kritik ohne Hilfe ...
Naja - manchmal stehe ich mir eben selbst im Wege :(
@Läubi
Danke für den Tip mit dem Fifo. Auch wenn es vielleicht nicht so gemeint
war - jedenfalls habe ich eine interessante Abhandlung zu dem Thema
gefunden und bei der Gelegenheit auch gleich gelernt, wie man mit
unterschiedlichen Taktdomainen umgeht.
Bei der Gelegenheit sind mir einige Warnungen aufgefallen:
Bei obigem Beispiel ist "BaseAddr" ein Generic Parameter.
Bei ModelSim erhalte ich die Warnung:
1
case choice must be locally static expression
Besteht dort Handlungsbedarf, oder kann ich die Warnung ignorieren?
Wie sieht das mit der Warnung aus, wenn ein std_logic_vector einen
(gewollten) Überlauf hat:
Muss ich den Fall für die Synthese besonders berücksichtigen, oder kann
die Warnung ignoriert werden?
Meine Implementierung anhand der Anleitung (die Abhandlung war für
Verilog geschrieben) funktioniert nur bei Altera zufriedenstellend. Bei
Xilinx ist das Teil sehr langsam. Klar kann man bei Xilinx ein Fifo
generieren lassen, falls möglich, möchte ich vorerst nur DCMs generieren
lassen.
Gibt es eine Möglichkeit, bei Xilinx zu erfahren, wo die Zeiten
entstehen/verloren gehen?
Ich habe mir zwar schon Timing-Auswertungen angeschaut, aber schlau
geworden bin ich daraus nicht.
Anfänger schrieb:
> Somit liegen die zu lesenden Daten am Ausgang an, sobald die Adresse> geschaltet wird.
Das sieht doch brauchbar aus, hier:
1
...else(others=>'0');
Kannst du besser so schreiben:
1
...else(others=>'-');
Dann sagst du der Synthese, das sie sich dort den Zustand aussuchen
darf, dass kann ggf etwas logik einsparen. (Wenn die Addresse nicht
gültig ist liegen halt ggf. auch keine gültigen Daten an)
> verändern sich die Lesedaten auch wenn eine andere Adresse beschrieben> werden soll. Da an dem 8Bit-Bus aber nur der Pico hängt, kann ich damit
Sollte kein Problem sein, da immer nur entweder gelesen oder geschrieben
wird, ansosnten benötigst du einen Addressport für lesen und einen zum
schreiben wie bei einem Dualport RAM
> Bei der Gelegenheit sind mir einige Warnungen aufgefallen:
Treat Warnings as Errors ;)
> Bei obigem Beispiel ist "BaseAddr" ein Generic Parameter.> Bei ModelSim erhalte ich die Warnung:
Irgenwo verwendust du in einem Case einen "nicht statischen parameter"
es wird meist weiter unten bestimmt noch ne Zeilennummer angegeben.
> Wie sieht das mit der Warnung aus, wenn ein std_logic_vector einen> (gewollten) Überlauf hat:
Ich würde den Überlauf abfangen. Macht nur Ärger in der Simulation, und
ggf. unerwartets Verhalten falls dein Integer irgenwann nichtmehr eine
Zweierpotenz ist. Sollte diese Prüfung überflüssig sein wird die
Synthese das schon wieder rausoptimieren...
> Meine Implementierung anhand der Anleitung (die Abhandlung war für> Verilog geschrieben) funktioniert nur bei Altera zufriedenstellend. Bei> Xilinx ist das Teil sehr langsam. Klar kann man bei Xilinx ein Fifo
??? Was fürn Fifo ich seh keinen ;)
Was heißt "sehr langsam"? Gibt es einen Grund das du immer für Xilinx
und Altera synthetisierst?
> Gibt es eine Möglichkeit, bei Xilinx zu erfahren, wo die Zeiten> entstehen/verloren gehen?> Ich habe mir zwar schon Timing-Auswertungen angeschaut, aber schlau> geworden bin ich daraus nicht.
Naja du kannst dir den kritischen Pfad anschauen aber ohne
Timingconstraint macht das nur bedinngt Sinn da wie shconmal erwähnt die
Systhese/Placer einfach abbrechen sobal es paßt.
> Treat Warnings as Errors ;)
Yepp - ist auch ne Grundeinstellung von mir. Nur oft weiß ich nicht, was
ich tun kann/soll.
Hier mal der "Case":
1
casei8bit.addris
2
whenaddrStatus=>...
3
whenaddrHigh=>...
4
whenaddrLow=>...
5
whenothers=>NULL;
6
endcase;
Es wird jede Konstante (s.o.) als "nicht konstant" angemeckert.
>> Wie sieht das mit der Warnung aus, wenn ein std_logic_vector einen>> (gewollten) Überlauf hat:> Ich würde den Überlauf abfangen. Macht nur Ärger in der Simulation, und> ggf. unerwartets Verhalten falls dein Integer irgenwann nichtmehr eine> Zweierpotenz ist. Sollte diese Prüfung überflüssig sein wird die> Synthese das schon wieder rausoptimieren...
Öhm, ich habe die Variable (bzw. das Signal) als std_logic_vector
deklariert und nicht als Integer. Bei Zählern, die ich als Integer
deklariere fange ich schon den Grenzwert ab.
Ich dachte, wenn ich einen Wert als z.B. 8Bit deklariere und einen
Überlauf haben will, dann bräuchte ich nix abfangen?!?
>> Meine Implementierung anhand der Anleitung (die Abhandlung war für>> Verilog geschrieben) funktioniert nur bei Altera zufriedenstellend. Bei>> Xilinx ist das Teil sehr langsam. Klar kann man bei Xilinx ein Fifo> ??? Was fürn Fifo ich seh keinen ;)Lach - ich habe einfach Dein Stichwort aufgegriffen, etwas gegurgelt
und dann die Beschreibung als Grundlage für ein Übungsbeispiel genommen
:)
(Ich habe keine Ahnung von Verilog, aber ich hänge mein Ergebnis
trotzdem mal an - mit Testbench. Im Gegensatz zu der Fifo von opencores
entspricht meine Variante eher meinen Erwartungen ;)
Falls jemand Verbesserungsvorschläge hat, sind die mir herzlich
willkommen)
> Was heißt "sehr langsam"? Gibt es einen Grund das du immer für Xilinx> und Altera synthetisierst?
Yepp! - Denn ich bin faul und würde es ohne Grund nicht tun ;)
Ich habe ein Übungsboard mit einem Xilinx drauf, empfinde aber die
Software von Altera (Quartus) als
benutzerfreundlicher/anfängerfreundlicher als die Xilinx-Software. Habe
mir dann einen halbwegs passenden Chip als Basis gesucht ... egal.
Zum Verständnis reicht es doch, wenn der Code übersetzt wird und das RTL
plausibel aussieht (Im RTL kann ich recht elegant überprüfen, ob ich
irgendwo ein FF vergessen oder falsch angesteuert habe).
Da jedoch bei Altera ganz andere Optimierungen (implizit) ablaufen,
kommen natürlich bei Xilinx völlig andere Maximalfrequenzen raus. Für
mich ist die Maximalfrequenz in erster Lesung ein Zeichen dafür, wie gut
meine Logik für den FPGA zugeschnitten wurde.
Bei Altera ist so 400MHz recht gut, über 200MHz nicht schlecht und unter
200MHz - sollte bei nächster Gelegenheit überarbeitet werden.
Bei Xilinx liegen die Maximalfrequenzen im Schnitt 30% niedriger. Wenn
dann aber mal weniger als die Hälfte rauskommt, dann gehen bei mir die
Alarmglocken an - ala: da besteht Handlungsbedarf.
Mit Timingconstraints habe ich bei Xilinx mal probiert - hat mich aber
nicht wirklich weiter gebracht, denn es wurde lediglich eine
Fehlermeldung ausgegeben, dass die Timingvorgaben nicht erfüllt werden
konnten.
Ich würde es als hilfreich empfinden, wenn einem der Pfad angezeigt
werden würde, der die Maximalfrequenz bestimmt (idealerweise im RTL) -
und zwar mit den Zeiten für jedes Segment, bzw. jedes Logikelement,
sodass man sehen (!) kann, wo Handlungsbedarf besteht. Keine Ahnung, ob
es sowas gibt.