mikrocontroller.net

Forum: FPGA, VHDL & Co. Codeoptimierung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Tycho B. (asellus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

bin Anfänger in VHDL und habe eine Frage zu diesem Codeteil:
clock_enable_count <= ('0' & "/"(count_100MHz,56)(16 downto 1)) + ((16 downto 1 => '0') & "/"(count_100MHz,56)(0));
limit <= count_100MHz/56;

Im Prinzip wird hier limit mit einem Wert geladen, der sich aus einer 
Division durch 56 ergibt.
Später im code wird der clock_enable_count mit limit verglichen, und 
eine weitere Variable inkrementiert um nicht mehr mit 100MHz zu takten, 
sondern mit einer passenden Frequenz.

Um Rundungsfehler zu vermeiden, wird clock_enable_count mit der Hälfte 
von (count_100MHz/56) geladen ZUSÄTZLICH +1 wenn (count_100MHz/56) 
ungerade ist.

Sorry wenn die Erklärung zu unverständlich und der Zweck nebulös wirken, 
aber das ist nicht der Punkt.

Sondern: Da die Division komplex in der Implementierung ist, wollte ich, 
dass diese nur ein mal ausgeführt wird. Nätürlich könnte man so etwas 
machen:
limit <= count_100MHz/56;
clock_enable_count <= ('0' & limit(16 downto 1)) + ((16 downto 1 => '0') & limit (0));

clock_enable_count wird jedoch erst mit der zweiten Ausführung des 
Codeblocks mit dem richtigen Wert geladen. Ich verliere also eine 
Taktflanke.

Deshalb habe ich den Teilungsteil im ersten Schnipsel überall gleich 
gestaltet in der Hoffnung, dass der Ausgang der Teilung für weitere 
Berechnungen verwendet wird.
Schematic zeigt jedoch zwei Teilungen. In Rot habe ich die Stelle 
markiert, wo ich einfach das nullte Bit abzweigen würde.
Geht das irgendwie?

Autor: Robotix (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
O(0) ist das Bit.
Du hast ausserdem überall 16 to 1, statt 16 to 0 stehen. Stimmt das?

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> Da die Division komplex in der Implementierung ist, wollte ich, dass
> diese nur ein mal ausgeführt wird.
Eine Division durch eine Konstante ist nicht zeitaufwändig, wenn man sie 
durch eine Multiplikation ersetzt und "übrige" Bits abschneidet. Die 
Berechnung

ergebnis = (wert*299593)/(2**24)

entspricht bis auf eine Genauigkeit von 1/3000000 stel der Division

ergebnis = wert/56

(exakt: ergebnis = wert/56,0000267). Und die Division 1/(2**24) wird 
einfach durch "Umverdrahten" erledigt, die unteren 24 Bits werden 
schlicht ignoriert.

> clock_enable_count wird jedoch erst mit der zweiten Ausführung des
> Codeblocks mit dem richtigen Wert geladen.
Da hast du irgendwo noch Latency mit eingebaut...

: Bearbeitet durch Moderator
Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robotix schrieb:
> O(0) ist das Bit.
Diese dünne Leitung aus dem zweiten Dividierer? Ja, denke ich auch. Ich 
will aber den zweiten Dividierer weg haben.

> Du hast ausserdem überall 16 to 1, statt 16 to 0 stehen. Stimmt das?
links muss das so, rechts kann auch 15 downto 0 stehen.

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> Tycho B. schrieb:
>> Da die Division komplex in der Implementierung ist, wollte ich, dass
>> diese nur ein mal ausgeführt wird.
> Eine Division durch eine Konstante ist nicht zeitaufwändig, wenn man sie
> durch eine Multiplikation ersetzt und "übrige" Bits abschneidet. Die
> Berechnung
>
> ergebnis = (wert*299593)/(2**24)
>
> entspricht bis auf eine Genauigkeit von 1/3000000 stel der Division
>
> ergebnis = wert/56
>
> (exakt: ergebnis = wert/56,0000267). Und die Division 1/(2**24) wird
> einfach durch "Umverdrahten" erledigt, die unteren 24 Bits werden
> schlicht ignoriert.

Dessen war ich mir überhaupt nicht bewust. Das werde ich mir genauer 
ansehen. Danke. Bedeutet das, dass der Compiler das als Multiplikation 
implementiert, weil ja bekannt ist, dass durch eine Konstante geteilt 
wird? Oder muss ich selbst ran?

>> clock_enable_count wird jedoch erst mit der zweiten Ausführung des
>> Codeblocks mit dem richtigen Wert geladen.
> Da hast du irgendwo noch Latency mit eingebaut...

Dann habe ich VHDL wohl nicht verstanden. Ich dachte, dass innerhalb 
eines Prozesses
measure: process (CLK100MHZ) begin              
   if (rising_edge(CLK100MHZ))then
      wert1 <= INPUT;
      wert2 <= wert1;
   end if;
end process measure;
mit der ersten Flanke wert1 INPUT bekommt und wert2 bekommt den alten 
wert1, der vor INPUT da war. Genau das würde bei mir passieren wenn ich 
die Division explizit ausführe
limit <= count_100MHz/56;
clock_enable_count <= ('0' & limit(16 downto 1)) + ((16 downto 1 => '0') & limit (0));

Autor: Tycho B. (asellus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Sooo...

Ich habe mich dunkel erinnert, dass es so etwas wie Variablen gibt. Bis 
jetzt noch nie verwendet.
v_limit := count_100MHz/56;
s_clock_enable_count <= ('0' & v_limit(16 downto 1)) + ((16 downto 1 => '0') & v_limit(0));
s_limit <= v_limit;

s_ - Signal
v_ - Variable

Und siehe da, genau wie ich es haben wollte. Bleibt nur noch die Frage 
ob der Compiler die Division als Multiplikation ausführt oder nicht?

Autor: Gustl B. (-gb-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dazu solltest du es schon so machen wie Lothar es vorgeschlagen hatte.

Autor: Dirk K. (merciless)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> ergebnis = (wert*299593)/(2**24)

Sorry für OT:
Wie kommt man darauf? Schlichtes Ausprobieren
oder gibt es da eine Näherungsformel/-Verfahren?

merciless

Autor: Gustl B. (-gb-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Durch 56 teilen ist eine Multiplikation mit der Zahl 1/56. Und das 
teilst du auf in die Division durch eine hohe Zweierpotenz und die 
Multiplikation mit einer normalen ganzen Zahl.

Also 1/56 = Zahl/Zweierpotenz. Die Zweierpotenz kannst du einfach groß 
genug wählen und dann die Zahl ausrechnen. Beispiel:
Zweierpotenz 1024, also folgt dass Zahl = (1/56)*1024 = 18,28...
Zweierpotenz 1048576, also folgt dass Zahl = (1/56)*1048576 = 
18724,57...

Du siehst also, dass die Rundungsfehler geringer werden wenn man eine 
größere Zweierpotenz wählt.

Ergebnis = (Wert*18724)/2^20

In VHDL kann man das (fast) so hinschreiben.

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> ergebnis = (wert*299593)/(2**24)
>
> entspricht bis auf eine Genauigkeit von 1/3000000 stel der Division
>
> ergebnis = wert/56

ich hab's mal spasseshalber mit Additionen gemacht. Ist auch zur 
Laufzeit eine Option:
-- 1/64 + 1/512 + 1/4096 + 1/8192 = 1/55.7xxxxx, 1/56 is target
clk_per_tick <= '0' & cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 6) +  -- 1/64
        cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 9) +  -- 1/512
        cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 12) +  -- 1/4096
        cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 13);  -- 1/8192
Das ganze fuer einen SENT-Protokoll Empfaenger, deshalb die Div durch 56 
mit hinreichender Genauigkeit

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> Oder muss ich selbst ran?
Ja. Der Synthesizer optimiert da von sich aus nichts.

Dirk K. schrieb:
> Wie kommt man darauf? Schlichtes Ausprobieren
Ich sags mal so: es gibt ein Verfahren, aber vor ich mich da wieder 
schlau mache, versuche ich es mit dem "Educated Guess" und probiere das 
in einer halben Minute durch, bis der Fehler hinreichend klein ist.
Das geht so: ich will 16 Bit Genauigkeit, dann beginne ich mit 256/56 
und merke mir 8. Dann multipliziere ich solange mit 2, bis die 
Nachkommastellen entweder 0 werden (Idealfall!) oder eben so klein, dass 
der Fehler hinreichend klein wird. Das ist spätestens der Fall, wenn 
65536 vor dem Komma steht (oder eben, wenn da 6553,67 stünde, denn auch 
diese 0,07 Abweichung sind hinreichend klein). Und jedesmal, wenn ich 
mit 2 multipliziere zähle ich eine Zehnerpotenz hoch. Zum Schluss ist 
der Multiplikator die Vorkommastellen und der Divisor die gezählten 
Zehnerpotenzen... 😉

: Bearbeitet durch Moderator
Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:
> Lothar M. schrieb:
>> ergebnis = (wert*299593)/(2**24)
>>
>> entspricht bis auf eine Genauigkeit von 1/3000000 stel der Division
>>
>> ergebnis = wert/56
>
> ich hab's mal spasseshalber mit Additionen gemacht. Ist auch zur
> Laufzeit eine Option:
 -- 1/64 + 1/512 + 1/4096 + 1/8192 = 1/55.7xxxxx, 1/56 is target
clk_per_tick <= '0' & cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 6) +  --1/64
cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 9) +  --1/512
cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 12) + --1/4096
cnt_arr (to_integer (state_cnt_end)) (REC_WCNT-1 downto 13);  --1/8192
 
> Das ganze fuer einen SENT-Protokoll Empfaenger, deshalb die Div durch 56
> mit hinreichender Genauigkeit

Ja, SENT)
Ich habe zwei Fragen zu deinem Code.

1. (REC_WCNT-1 downto 12) Ich dachte es gibt keinen Präprozessor. Wie 
definierst du die Konstante REC_WCNT, mit constant?

2. cnt_arr (to_integer (state_cnt_end)) Was macht diese Struktur?

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> Tycho B. schrieb:
>> Oder muss ich selbst ran?
> Ja. Der Synthesizer optimiert da von sich aus nichts.
>
> Dirk K. schrieb:
>> Wie kommt man darauf? Schlichtes Ausprobieren
> Ich sags mal so: es gibt ein Verfahren, aber vor ich mich da wieder
> schlau mache, versuche ich es mit dem "Educated Guess" und probiere das
> in einer halben Minute durch, bis der Fehler hinreichend klein ist.
> Das geht so: ich will 16 Bit Genauigkeit, dann beginne ich mit 256/56
> und merke mir 8. Dann multipliziere ich solange mit 2, bis die
> Nachkommastellen entweder 0 werden (Idealfall!) oder eben so klein, dass
> der Fehler hinreichend klein wird. Das ist spätestens der Fall, wenn
> 65536 vor dem Komma steht (oder eben, wenn da 6553,67 stünde, denn auch
> diese 0,07 Abweichung sind hinreichend klein). Und jedesmal, wenn ich
> mit 2 multipliziere zähle ich eine Zehnerpotenz hoch. Zum Schluss ist
> der Multiplikator die Vorkommastellen und der Divisor die gezählten
> Zehnerpotenzen... 😉

Das Verfahren ist sehr einfach, nennt sich Dreisatz.

1/56 = x/2^24, x ausrechnen und runden.

Anstelle 2^24 beliebige Zweierpotenz einsetzen. Je höher die 
Zweierpotenz desto genauer die Approximation.

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> 1. (REC_WCNT-1 downto 12) Ich dachte es gibt keinen Präprozessor. Wie
> definierst du die Konstante REC_WCNT, mit constant?
ist ein generic den ich uebergebe. Damit werden die clock-counter 
definiert (z.B. 16 bit breit)

>
> 2. cnt_arr (to_integer (state_cnt_end)) Was macht diese Struktur?
das ist ein Array mit 16 entries, in dem werden die Clock-counts der 
letzten 16 Symbole (SYNC, S&C, D0..D5, CRC, PAUSE) abgelegt

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> Das Verfahren ist sehr einfach, nennt sich Dreisatz.
Schon, aber dieser triviale Ansatz ignoriert ein "lokales 
Genauigkeitsmaximum", das ggfs schon bei weniger Stellen ein hinreichend 
genaues Ergebnis liefern würde.

> Je höher die Zweierpotenz desto genauer die Approximation.
Im Prinzip ja, aber wenn ich z.B. x/33 rechnen will, dann reichen mir 
x*31/(2**10) für eine Genauigkeit von 1/1000, weil der genaue Faktor 
eigentlich x*31,0303/1024 wäre:
                        Ideal               Real im FPGA   Fehler
2**8/33  = 7,7575   ==> x*7,7575/256        x*8/256        3,1%
2**9/33  = 15,5151      x*15,5151/512       x*16/512       3,1%
2**10/33 = 31,0303      x*31,0303/1024      x*31/1024      0,09%
2**11/33 = 62,0606      x*62,0606/2048      x*62/2048      0,09%
2**12/33 = 124,1212     x*124,1212/4096     x*124/4096     0,09%
2**13/33 = ...          x*248,2424/8192     x*248/8192     0,09%
2**14/33 = ...          x*496,4848/16384    x*496/16384    0,09%
2**15/33 = ...          x*992,9696/32768    x*993/32768    0,003%
2**16/33 = ...          x*1985,9393/65536   x*1986/65536   0,003%
2**17/33 = ...          x*3971,8787/131072  x*3972/131072  0,003%
2**18/33 = ...          ...                                0,003%
2**19/33 = ...          ...                                0,003%
2**20/33 = 31775,0303                                      0,00009%
2**21/33 = ...                                             0,00009%
...
Hier sieht man, dass diese Faustformel eben nicht uneingeschränkt gilt, 
denn von 2**10 bis 2**14 ist der Fehler der Rechnung immer gleich groß.

> ausrechnen und runden.
Denn der Witz ist: wenn die gewählte Zweierpotenz ungünstig ist und der 
gerundete Wert genau bei x,5 liegt, dann ist die Abweicung maximal. Im 
Idealfall nimmt man eben einen Faktor, der, geteilt durch die 
entsprechende Zweierpotenz, genau x,000 gibt. Dann ist die gewünschte 
Division optimal und ohne Fehler implementiert. Fazit: generell sind 
Faktoren mit geringstmöglicher Rundung optimal.

: Bearbeitet durch Moderator
Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> Tycho B. schrieb:
>> Das Verfahren ist sehr einfach, nennt sich Dreisatz.
> Schon, aber dieser triviale Ansatz ignoriert ein "lokales
> Genauigkeitsmaximum", das ggfs schon bei weniger Stellen ein hinreichend
> genaues Ergebnis liefern würde.
Ich habe mal den Fehler von 1/33 bis 1/200 durchgeplottet (von 2^8 bis 
2^38), es gibt nirgends ein lokales Genauigkeitsmaximum, der Verlauf des 
Fehlers ist monoton fallend (nicht streng monoton!). Man kann es also 
mit mehr Stellen nicht schlechter machen. Ansonsten stimme ich zu, man 
muss nicht unbedingt 2^32 nehmen, es kommt auf den zu akzeptierenden 
Fehler an.

>> ausrechnen und runden.
> Denn der Witz ist: wenn die gewählte Zweierpotenz ungünstig ist und der
> gerundete Wert genau bei x,5 liegt, dann ist die Abweicung maximal. Im
> Idealfall nimmt man eben einen Faktor, der, geteilt durch die
> entsprechende Zweierpotenz, genau x,000 gibt. Dann ist die gewünschte
> Division optimal und ohne Fehler implementiert. Fazit: generell sind
> Faktoren mit geringstmöglicher Rundung optimal.

Wie gesagt, im ungünstigsten Fall führt die Einführung einer weiteren 
Zweierpotenz zum gleichen Fehler, niemals größer.

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:
> Tycho B. schrieb:
>> 1. (REC_WCNT-1 downto 12) Ich dachte es gibt keinen Präprozessor. Wie
>> definierst du die Konstante REC_WCNT, mit constant?
> ist ein generic den ich uebergebe. Damit werden die clock-counter
> definiert (z.B. 16 bit breit)
>
>>
>> 2. cnt_arr (to_integer (state_cnt_end)) Was macht diese Struktur?
> das ist ein Array mit 16 entries, in dem werden die Clock-counts der
> letzten 16 Symbole (SYNC, S&C, D0..D5, CRC, PAUSE) abgelegt

Das heisst du teils jedes Nibble durch 56?

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> es gibt nirgends ein lokales Genauigkeitsmaximum
Das hatte ich evtl. falsch rübergebracht: das Verhältnis 
"Genauigkeit/Wortbreite" hat lokale Maxima. Und das kann sich dann ggfs. 
in Richtung "Genauigkeit/Aufwand" auswirken.

> Wie gesagt, im ungünstigsten Fall führt die Einführung einer weiteren
> Zweierpotenz zum gleichen Fehler, niemals größer.
Oder mit anderen Worten: für das gleich gute Ergebnis können durchaus 
auch weniger Bits ausreichen. Und damit ggfs. der beteiligte 
Multiplizierer anders/effizienter implementiert werden. So lässt sich 
hier die Multiplikation (x*31) ganz leicht so darstellen (x&"00000" - 
x). Mit (x*124) sieht man das nicht so leicht (obwohl es im Prinzip das 
selbe ist: x&"0000000"-x&"00")...

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> Tycho B. schrieb:
>> es gibt nirgends ein lokales Genauigkeitsmaximum
> Das hatte ich evtl. falsch rübergebracht: das Verhältnis
> "Genauigkeit/Wortbreite" hat lokale Maxima. Und das kann sich dann ggfs.
> in Richtung "Genauigkeit/Aufwand" auswirken.
Bin einverstanden)

>> Wie gesagt, im ungünstigsten Fall führt die Einführung einer weiteren
>> Zweierpotenz zum gleichen Fehler, niemals größer.
> Oder mit anderen Worten: für das gleich gute Ergebnis können durchaus
> auch weniger Bits ausreichen. Und damit ggfs. der beteiligte
> Multiplizierer anders/effizienter implementiert werden. So lässt sich
> hier die Multiplikation (x*31) ganz leicht so darstellen (x&"00000" -
> x). Mit (x*124) sieht man das nicht so leicht (obwohl es im Prinzip das
> selbe ist: x&"0000000"-x&"00")...

Wenn man von c kommt, dann denkt man gar nicht mehr daran...
Zum Einen sind die Operationen schon in Logik gegossen, auch Division, 
zum Anderen optimiert der Compiler den sonstigen Rest.
Ist es so, dass der Synthetisierer so etwas wie dein Beispiel nicht 
erkennt? Wie gut sind die Optimierungen dieser Tools? Kann man am 
schematic erkennen wie es implementiert wurde?

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> Das heisst du teils jedes Nibble durch 56?

das laeuft halt frei mit. Im Prinzip finde ich durch vergleichen der 
Clock-counter heraus, wo der SYNC liegt. Der geteilt durch 56 gibt mir 
dann die Ticktime, die ich fuer was anderes wieder benoetige

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:
> Tycho B. schrieb:
>> Das heisst du teils jedes Nibble durch 56?
>
> das laeuft halt frei mit. Im Prinzip finde ich durch vergleichen der
> Clock-counter heraus, wo der SYNC liegt. Der geteilt durch 56 gibt mir
> dann die Ticktime, die ich fuer was anderes wieder benoetige

Das habe ich mir auch überlegt, aber da die tick time zw. 3 und 90 
liegen kann und gleichzeitig ein Pausenpuls vorliegen kann, der zwischen 
12 und 768 ticks liegt, ist es schwierig z.B. den Pausenpuls vom sync zu 
unterscheiden wenn man zuvor nicht die nominelle tick time vorgibt, 
oder?

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> ist es schwierig z.B. den Pausenpuls vom sync zu
> unterscheiden wenn man zuvor nicht die nominelle tick time vorgibt

der worst-case waere, wenn der SYNC faelschlicherweise als 27 Ticks im 
Vergleich zum PAUSE waere. Dann waere weiterhin gefordert, dass die 
'laengste' gueltige SENT Botschaft =0xFFFEFFFE immer noch als mindestens 
12 Ticks berechnet wuerde. Das passt nicht! For allem, weil ja zum 
Beispiel der S&C ueblicherweise nur 4, 8, oder 12 als numerischen Wert 
hat (slow-channel).

Autor: Christophz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> Kann man am
> schematic erkennen wie es implementiert wurde?

Es gibt üblicherweise zwei verschiedene Schematics die du ansehen 
kannst: RTL Schematic und Technology Schematic (So heisst es in 
Synplify) bzw. Schematic beim Design-Flow Schritt "Synthesize" und 
Schematic beim Design-Flow Schritt "Map" (Das müsste etwa so zu finden 
sein in Vivado und Diamond).

Das RTL Schematic ist das, was du uns als Screenshot gegeben hast. Das 
ist im Prinzip die Darstellung was der Synthesizer verstanden hat (Im 
Compiler Bau vergleichbar zum Abstract Syntax Tree). Das müsste grob dem 
entsprechen, was du vorher als Blockdiagramm geplant hattest.

Das Technology Schematic bildet die selbe Funktionalität ab, nutzt dazu 
aber Elemente, die in deiner Zielhardware vorhanden sind. Dies variiert 
also zwischen verschiedenen FPGA Typen (Beim Compiler vergleichbar mit 
dem Assembler Listing).

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> der worst-case waere, wenn der SYNC faelschlicherweise als 27 Ticks im
> Vergleich zum PAUSE waere. Dann waere weiterhin gefordert, dass die
> 'laengste' gueltige SENT Botschaft =0xFFFEFFFE immer noch als mindestens
> 12 Ticks berechnet wuerde. Das passt nicht! For allem, weil ja zum
> Beispiel der S&C ueblicherweise nur 4, 8, oder 12 als numerischen Wert
> hat (slow-channel).

Hm.
Nehmen wir mal als Basis die tick time und folgende Sequenz:
Pausenpuls, sync, 8*Nibble
und als Zeiten(tick time als 1):
115, 56, 8*27 (ich betrachte mal die zwei 0xE als 0xF)
rechnet man 115 als sync, dann bekommt man:
56, 27, 7*13 + 13     (die letzte 13 wird als Pausenpuls interpretiert)
56 + 27 + 7*13 = 174 ist größer als Mindestlänge von 154 ticks.

Oder habe ich dich falsch verstanden?

Autor: Tycho B. (asellus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Christophz schrieb:
> Es gibt üblicherweise zwei verschiedene Schematics die du ansehen
> kannst: RTL Schematic und Technology Schematic (So heisst es in
> Synplify) bzw. Schematic beim Design-Flow Schritt "Synthesize" und
> Schematic beim Design-Flow Schritt "Map" (Das müsste etwa so zu finden
> sein in Vivado und Diamond).
>
> Das RTL Schematic ist das, was du uns als Screenshot gegeben hast. Das
> ist im Prinzip die Darstellung was der Synthesizer verstanden hat (Im
> Compiler Bau vergleichbar zum Abstract Syntax Tree). Das müsste grob dem
> entsprechen, was du vorher als Blockdiagramm geplant hattest.
>
> Das Technology Schematic bildet die selbe Funktionalität ab, nutzt dazu
> aber Elemente, die in deiner Zielhardware vorhanden sind. Dies variiert
> also zwischen verschiedenen FPGA Typen (Beim Compiler vergleichbar mit
> dem Assembler Listing).

Vielen Dank für die Erklärung!
Und so sieht es in Vivado aus...

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> Oder habe ich dich falsch verstanden?

1. Dein PAUSE Puls ist ungewoehnlich lang
2. Dein S&C wuerde noch startup und error anzeigen
3. Deine CRC waere falsch
4. Der Wert 0xFFF fuer die FC-Daten bedeuted ueblicherweise einen Fehler

Fehlerwahrscheinlichkeit also annaehernd Null, ausserdem kannst du 
folgende Botschaften ja mit der berechneten Ticktime plausibilisieren.
Laeuft hier seit (gerade nachgeguckt) 2012 ohne Probleme.

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
achso, nochwas:

5. Beim naechsten Nibble wuerdest du ja wieder den Prozess anschmeissen 
und eine gueltige Message finden. Auch das kannst du zum 
plausibilisieren ausnutzen

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:
> Tycho B. schrieb:
>> Oder habe ich dich falsch verstanden?
>
> 1. Dein PAUSE Puls ist ungewoehnlich lang
> 2. Dein S&C wuerde noch startup und error anzeigen
> 3. Deine CRC waere falsch
> 4. Der Wert 0xFFF fuer die FC-Daten bedeuted ueblicherweise einen Fehler
>
> Fehlerwahrscheinlichkeit also annaehernd Null, ausserdem kannst du
> folgende Botschaften ja mit der berechneten Ticktime plausibilisieren.
> Laeuft hier seit (gerade nachgeguckt) 2012 ohne Probleme.

1. Eher normal. Pausenpuls wird verwendet um Frames konstanter Dauer zu 
produzieren. Bei z.B. 3us tick time und 1ms Frame ist der Pausenpuls 
zwischen ca. 63 und 183 ticks.
2. Ja
3. Alle? Es gibt ja einige mögliche Kombinationen. Der CRC hat auch 
einen gewissen Fehler. Muss ich nachrechnen, kann aber sein.
4. Ja
5. Klappt nicht. Wenn man diese Logik verwendet, so würde man bei einem 
Frame ohne Pausenpuls eventuell trotzdem einen detektieren, z.B.:
56, 27, 7*13
Wenn der Prozess bei 27 neu startet, so kann 27 als sync interpretiert 
werden, 13 als 27 und 56 als Pausenpuls.

Die Synchronisierung anhand der Punkte 2-4 ist indirekt, d.h. es müssen 
schon alle Werte dekodiert worden sein, um Entscheidung zu treffen. Ich 
habe gehofft eine direkte Methode finden zu können, die sich allein aus 
Pulslängen ableiten lässt. Das ist im FPGA deutlich einfacher zu 
implementieren, imho.

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tycho B. schrieb:
> würde man bei einem
> Frame ohne Pausenpuls eventuell trotzdem einen detektieren, z.B.:
> 56, 27, 7*13

deine Daten (max 27 Ticks) muessen kleiner als ein halber SYNC (56 
Ticks) sein. Das klappt ganz sicher da 2x27=54 ist

Autor: Tycho B. (asellus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:
> Tycho B. schrieb:
>> würde man bei einem
>> Frame ohne Pausenpuls eventuell trotzdem einen detektieren, z.B.:
>> 56, 27, 7*13
>
> deine Daten (max 27 Ticks) muessen kleiner als ein halber SYNC (56
> Ticks) sein. Das klappt ganz sicher da 2x27=54 ist

Wenn man diese Sequenz nimmt:
56, 27, 7*13
und 27 als sync interpretiert, so ist 13 (und 12 sowieso) kleiner als 
die Hälfte.
So kann 56 Pausenpuls sein, 27 sync und der Rest Daten.

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... dann hast du aber ein Symbol zu wenig empfangen!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.