Forum: FPGA, VHDL & Co. Frage(n) zur Schnittstelle Picoblaze


von Anfänger (Gast)


Lesenswert?

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).

von Michael Sauron (Gast)


Lesenswert?

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.

von Anfänger (Gast)


Lesenswert?

> 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.

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Michael Sauron (Gast)


Angehängte Dateien:

Lesenswert?

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
   case port_id is
4
      when x"00" => in_port_i <= i0;                   -- port  0
5
      when x"01" => in_port_i <= i1;                   -- port  1
6
      when x"02" => in_port_i <= i2;                   -- port  2
7
      when others => in_port_i <= (others =>'-');
8
   end case;
9
end process;
10
11
process (clk) begin                                  --in_port pipeline 
12
  if rising_edge (clk) and read_strobe = '0' then
13
    in_port <= in_port_i;
14
  end if;
15
end process;

hier werden 3 Ports für den Picoblace gemultiplext

von Anfänger (Gast)


Lesenswert?

> 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
if rising_edge (clk) and read_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?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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
if rising_edge (clk) then
2
 if read_strobe = '1' then
3
  output_port <= meine_neuen_daten;
4
 end if;
5
end if;

> 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!

von Michael Sauron (Gast)


Lesenswert?

> 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
if rising_edge (clk) and read_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

von Anfänger (Gast)


Lesenswert?

>>> 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!

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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...

von Anfänger (Gast)


Lesenswert?

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:
1
ARCHITECTURE std of APMemVar12 IS
2
   constant addrStatus : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(BaseAddr, 8));
3
   constant addrHigh   : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(BaseAddr + 1, 8));
4
   constant addrLow    : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(BaseAddr + 2, 8));
5
   signal memvar : std_logic_vector(11 downto 0) := (others=>'0');
6
   signal status : std_logic_vector(1 downto 0)  := STAT_UNDEF;
7
BEGIN
8
   o8bit.data <= "000000" & status            when i8bit.addr = addrStatus else
9
                 "0000" & memvar(11 downto 8) when i8bit.addr = addrHigh   else
10
                 memvar(7 downto 0)           when i8bit.addr = addrLow    else
11
                 (others=>'0');
12
13
   PROCESS
14
   BEGIN
15
      ...
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:
1
# ** Warning: NUMERIC_STD.TO_UNSIGNED: vector truncated
2
#    Time: 322200 ns  Iteration: 2  Instance: /testbench/myasyncfifo/writeptr_full
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.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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.

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

> 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
         case i8bit.addr is
2
         when addrStatus => ...
3
         when addrHigh   => ...
4
         when addrLow    => ...
5
         when others     => NULL;
6
         end case;
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.

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.