78 Downloads haben mich motiviert, nochmal richtig Gas zu geben um die Einsen im Vektor zu zählen ;-) Das Beispiel zeigt, dass man die Synthese doch extrem pushen kann, wenn man nachhilft. Ergebnis: Nur noch 501 Logikelemente im Cyclone II (vorher 1285), max Laufzeit Pin- to Pin jetzt nur noch knappe 22 ns ! Das entspricht einem Durchsatz von 11 GBits/s, wenn ich mich jetzt nich verzählt habe... Funktions-Prinzip : siehe letzter Beitrag dazu + Anhang Man beachte die Funktion bits2num, die "mundgerecht" für die Synthese eine Lookup-Table beschreibt.
Puh... rspekt... da muss ich aber vom verständniss so langsam passen. Aber ich werd es mir glaich noch mal in ruhe verinnerlichen. Ist VHDL deine Muttersprache :-)???
Hm VHDL dürfte wohl nicht seine Geburtssprache sein, das dürften nur Ausserirdische mit der Muttermilch trinken, denoch Respekt. Wenn ich das richtig sehe wird per Lookup Tabelle für 4 Bit breite Vektoren die Anzahl der Bits direkt nachgeschlagen. Da wird aber einen 256 Bit Vektor auswerten benötigen wir also 256 / 4 = 64 Zwischenspeicher a 3 Bit. Nun meine erste Frage warum nutz du type LOOK_UP_TYPE is array (0 to 63) of std_logic_vector(3 downto 0); statt type LOOK_UP_TYPE is array (0 to 63) of std_logic_vector(2 downto 0); denn wir benötigen für die Bitanzahlen für einen 4 Bit Vektor doch nur 0..4 ergo ein 3 Bit breiter Vektor müsste doch reichen ? Antwort könnte sein das in der untersten Ebene deiner Additions-Pyramide, also hier add1(k) <= (look_up(2*k) + look_up(2*k+1)); ansonsten diese so aussehen müsste add1(k) <= ('0' & look_up(2*k) + '0' & look_up(2*k+1)); richtig ? Denoch meine ich das die Function bit2num() und LOOK_UP_TYPE mit einem std_logic_vector(2 downto 0) auskommen könnten. Im weiteren Verlauf addierst du wie in einer Pyramide, echt clever. Hast du schon mal getestet wie der Resourcenverbrauch aussieht wenn man bin2num auf 7 Bits umbaut ? Ich weiß 7 Bits hören sich ersteinmal dumm an da 256 nicht ohne Rest durch 7 teilbar ist. Aber das liese sich ja mit entsprechenden '0' Bits auffüllen. Wichtig ist dabei nur das so ein 7 Bit Vektor auch nur 0 bis 7 gesetzte 1 Bits enthalten kann. Die weitere Platzersparnis dürfte dir ja klar sein. 7->14->28 usw. usw. nutzen die LE's wahrscheinlich besser aus. Gruß Hagen
@Hagen hat sich also doch noch ein Fehler eingeschlichen, in diesem Fall hats die Synthese aber bemerkt, die neue Version im Anhang benötigt trotzdem 501 LEs, aber hast natürlich recht, 3 bits reichen für die max. 4 die hier auftreten können. Gut gesehen !
Ja, ich hatte die Nacht schon eigene Experimente mit deinem Source durchgeführt und auch festgestellt das sich nichts am Resourceverbrauch geändert hat. Es ist sowieso sehr seltsam das die Synthesetools zweitweise echt clever optimieren, das man sich schon fragt wie die so intelligent sein können, andereseits aber manchmal aus einem einfachen VHDL den größten Schrott synthetisieren. Du sagst das du das VHDL für einen CycloneII synthetisiert hast, also wohl QuartusII benutzt hast. Wie hast du dort die Testbench + den ModelSim angesprochen. Ich habs noch nie hinbekommen im shit QuartusII eine VHDL Testbench für die Simulation zum laufen zu bekommen. Deshalb bevorzuge ich eigentlich auch das Xilinx WebPack, das scheint mir vom GUI her sauberer programmiert zu sein. (die scheiß ständigen MessageDlg's beim Quartus nerven echt) zZ. versuche ich mit einem komplett anderen Verfahren dein Verfahren zu unterbieten, mal sehen ob ich das schaffe ;) Gruß Hagen
@Hagen ja, ich benutze den Quartus II und ModelSim ALTERA. Die funktionale Simulation mache ich immer nur separat mit dem ModelSim, als gäbe es praktisch keine Quartus-SW. Die Testbench schreibe ich immer selber in VHDL, wenn es einfach ist, dann gibts eben eine tb.vhd, wo meine Top-Level entity als component drin vorkommt und Takte, Reset und Input-Stimuli als VHDL beschrieben sind. Wenns umfangreicher wird, dann schreibe ich 1 oder mehrere stimuli.vhd, die in der tb eingebunden sind. Für eine Test-Synthese wird im Quartus II einfach mit dem Project-Wizard fix ein Projekt angelegt und die Source-Files angegeben, dann aufs Knöpfchen drücken und die lustigen Messages verfolgen, allerdings finde ich die ganzen graf. Tools teilweise sinnlos und mit Funktionen überfrachtet, wobei die Übersicht eben leidet. Pinout-Files gebe ich beim Quartus schon lange als TCL-Files ein, da tu ich mich mit Änderungen wesentlich leichter und muss nicht in irgendwelchen Quartus-Projektfiles oder in langsamen GUIs rumoperieren.
Super, aber WIE machst du das ? Ich meine wie bindest du die Testbench + den Aufruf vom ModelSim Altera ein ? Ich habe in den Projektoptionen ebenfalls den ModelSim Altera eingestellt und dort im Dlg auch das Testbench VHDL angegeben, allerdings verlangt das Mistding eine *.VHT Datei statt einer *.VHDL Datei, egal ich habe deine Datei einfach umbenannt. Nur kommt dann eine Fehlermeldung das er ".vcom" nicht finden kann, was auch immer er damit sucht ? Ich habe die Freeedition aus dem WEB, kann es daran liegen ? Gruß Hagen PS: nichts gegen Quartus II aber das Xilinx WebPack halte ich für intiutiver (zumindestens als Programmierer der eh shit C/C++ IDE's gewöhnt ist).
ich starte den ModelSim einfach im Windows und arbeite dann im GUI vom ModelSim. - ModelSim aufmachen - Projekt anlegen - Files hinzufügen (bitcount.vhd, tb.vhd) - Files compilieren - vsim-Kommando (vsim tb) - Wave-Fenster Signale hinzufügen - run xxx ns eintippen - fertig -> kleines *.do-File als Script macht die Arbeit leichter hab Dich vielleicht missverstanden, aber das läuft alles separat ohne Quartus, da sind keine Querverbindungen nötig.
Hi Ich will Deine Arbeit nicht schlecht reden, aber diese Lösung würde ich auf keinen Fall einsetzen. Sie sieht in der Simulation ja schön aus, jedoch stell Dir mal Deine Schleifen in Hardware vor, und dann sind die se noch alle asyncron. Was da alles passieren kann. Das wichtigste ist immer ein synchrones Design, es sei denn man schreibt ein Constraint-File und gibt alle Laufzeiten vor, damit man ein gewissen Sicherheitsfaktor hat. Ändert sich die Temperatur, dann hat die Logik ein anderes Schaltverhalten, so das es eventuell zu Laufzeitproblemen kommen kann und das ganze nicht mehr funktioniert. Dies kann doch auf dem FPGA nicht richtig funktionieren. Und dann einen Fehler zu finden ist so gut wie unmöglich. Hast Du schon mal eine Timing-Simulation gemacht? Warum muss das ganze denn asynchron geschenen? DIN kann doch auch seriell gefüllt werden und dabei kann man doch gleich mitzählen. Ich kann mir nicht vorstellen, dass Du 255 Leitungen an die Ports legen möchtest (den Datenbus will ich mal sehen) Grüsse Michael
@Michael Sorry, Du hast da was falsch verstanden, das ganze sollte nur ein Beispiel und zum Lernen gedacht sein, entsprungen aus einer Frage im Forum. Natürlich würde ich die Bits seriell schieben und zählen wenns geht, aber die Vorgabe war, dass ein 256 bit Vector im FPGA parallel existiert und die Einsen gezählt werden sollten. Was soll hier asynchron sein? Wenn die Bits aus einem Register kommen und Du ein 9 bit Register hier an den Ausgang legst, dann ist alles synchron ! Das funktioniert in jedem FPGA, da geb ich Dir Brief und Siegel, und nicht mal langsam ! Die Synthese mit den 256 Ports war nur mal um zu sehen, wieviele Ressourcen benötigt werden. Hagen hat die Aufgabe auch sehr sportlich gesehen, bin mal gespannt, ob der eine effizientere Lösung findet. Man kann sehr viel daraus lernen, finde ich - auch wenn man sich mal von anderen Anregungen holt, es gibt hier viel interessantes an VHDL zu sehen.
nochmal zur Timing-Simulation: Das reale Design braucht 21,nochwas ns längste Tpd von einem Input-Pin zum Ausgang im gewählten Cyclone II, im gesamten Temperaturbereich und auch bei der niedrigsten Versorgungsspannung. Das sagt der Quartus II Timing-Analyzer, nachdem alles im Cyclone geroutet war, ich könnte das Design so ins FPGA reinladen und es würde (mit den gedachten Registern an Ein- und Ausgang) bis 45 MHz Clock-Frequenz funktionieren. Mit den Registern würde ein simples Clock-Constraint reichen, das man ja sowieso hat (alles ist synchron).
Jo, den Einwand von Michael habe ich auch nicht so recht verstanden. Die Laufzeit ist nach der Synthese doch fest und sozusagen unveränderlich, mal abgesehen von der Temperatur und Spannung am FPGA. Asynchron heist für mich aber das ein beliebiges Ereignis nicht vorhersagbar zum restlichen synchronen Design auftreten kann. Das hat dann nichts mehr mit einer fixen kombinatorischen Logik zu tun deren Laufzeit im Grunde unabhängig vom zu bearbeitenden Dateninhalt ist. @FPGA-User: kannst du dich an die clerveren BitCount Algorithmen für normale PC's erinnern ? Denn mit and $AAAAAAA,$5555555 usw. ? Den versuche ich zu portieren. Gruß Hagen
Hi FPGA-User, wenn du mich sehen könntest so würdest du in ein ziemlich erstauntes Gesicht blicken. Anbei meine Lösung des Problemes, natürlich kombinatorisch. Sie benötigt auf einem Cyclone II exakt 510 LE's und in deinem Maßstab eine Laufzeit von 22ns, ja richtig gelesen ;) Bei meiner Synthese deines und meines VHDL's zeigt er mir was von Tpd = 25.xx an. Mit welchen Einstellungen bist du auf die 22.xx ns gekommen ? Vorteil meiner Lösung dürfte die Function Bits() sein die die Anzahl der gesetzten Bits eines 32 Bit breiten Vektors errechnet. Sie benötgt 56 LE's. Ich schätze mal das man meinen Sourcenoch schöner machen kann, sprich Loops und dynamische Vektorengrößen. Aber egal für 2 Stunden nächtliche Tipperei bin ich eigentlich überrascht wie simpel es doch war. Hat Spaß gemacht ;) Gruß Hagen
Sorry, sie benötigt 501 LE's, also so wie deine Lösung. Gruß Hagen
@Hagen wirklich gut, den Algorithmus kannte ich noch nicht. Ich lass mich mal dazu hinreißen zu behaupten, dass 501 LEs das Minimum sind, wenns mit reiner Kombin. ohne FPGA-spezische Funktionen gelöst wird. So jetz is aber gut, sonst wird noch jemand böse, wolln ja keine VHDL-Conteste hier austragen ;-))))
Hm, ich bin denoch der Meinung das es eventuell besser geht, ich habe aber nur eine Idee und weiß nicht wie ich sie umsetzen soll. Bei deinem und meinem Verfahren ist doch das Problem das wir beim Zählen der Einsen die Anzahl im späteren Verlauf nicht optimal speichern. Also aus einem "11 10" Vektor wird in der 1. Stufe die Anzahl in einen 4Bit Vektor in der Art "2 1"-> "10 01" gespeichert. Das liegt daran weil wir nur dual splitten, wir sollten aber in Dreiergruppen splitten und deren Anzahlen in 2 Bit Vektoren speichern, also aus "111 010" wird "3 1" -> "11 01". Wir würden also die FF's/LE's die die Anzahlen speichern besser ausnutzen. In der zweiten Stage würde wir maximal 3+3 = 6 in einem 3 Bit Vektor speichern, also wieder 1 Bit an Information verloren. Deshalb würde ich einzelne Bit-Teile des Eingangsvektors in der 1. Stage ignorieren dafür aber in der 2. Stage nun hinzuaddieren. Somit erhöhen wir die Werigkeit der max. möglichen Anzhal von 3+3 auf 3+3+1 = 7 und speicher diese Anzahl in einem 3 Bit Vektor. Das geht mit der dritten Stage so weiter, 7+7=14 + 1 Bit aus Eingangsvektor = 15 in einem 4 Bit Vektor zusammenadiert. Konntest du meinen wirren Ideen folgen ? Gruß Hagen
@Hagen jetzt müsstest Du aber mal mein Gesicht sehen ! Ich hab mir nochmal die Ergebnisse im Quartus angeschaut und siehe da - unsere beiden VHDL-Codes liefern exakt dasselbe Ergebnis (die Zeitdiff. kommt entweder von versch. Speed-Grades oder Programmversionen, hab hier die 5.0 Vollversion) d.h. beide Files werden exakt gleich implementiert ! (s. RTL-Viewer und Resource Usage Details) 192 x 4-Inp. Funktionen 246 x 3-Inp. Fkt. 63 x <= 2 Inp. Fkt. Und um noch einen draufzusetzen, im Anhang noch eine Variante die exakt dieses Ergebnis liefert (das war aber jetzt wirklich die letzte Version von mir) -> vielleicht gehts ja noch besser, wenn man die Bitbreiten besser ausnutzt aber bei 3 gleichen Ergebnissen mit 3 versch. Beschreibungen glaub ich nich mehr dran. -> VHDL is FUN
Jo a1 := std_logic_vector'('0' & inp(0)) + std_logic_vector'('0' & inp(1)); a2 := std_logic_vector'('0' & inp(2)) + std_logic_vector'('0' & inp(3)); a3 := std_logic_vector'('0' & inp(4)) + std_logic_vector'('0' & inp(5)); a4 := std_logic_vector'('0' & inp(6)) + std_logic_vector'('0' & inp(7)); das sehe ich auf den ersten Blick das das identisch zu meinem BitCount() ist, eben nur für 8 Bit breite Vektoren. Abwandlung zu meiner obigen Idee wäre es nun so a1 := std_logic_vector'('0' & inp(0)) + std_logic_vector'('0' & inp(1)) + std_logic_vector'('0' & inp(2)) ; zu rechnen. Ich vermute das liegt an der Art & Weise wie der Fitter die Boolschen Verküpfungen optimiert. Wenn ich richtig informiert bin gibt es theoretische Abhandlungen von Matematikern die die Optimierung von riesigen Boolschen Vernetzungen = Formel über Matrizen beschreiben. Dabei wird immer das Optimum gefunden ! Aber auch ich meine, wenn der Fitter schon so "intelligent" ist, das eine weitere Beschäftigung mit dem Thema nicht wirklich neues für uns bringen wird. Ich warte schon auf den nächsten Lernstoff ;) Gruß Hagen
Ich hab mich schon die ganze Zeit gefragt, was das alles für einen Nährwert haben soll und hab mir den Ursprungsthread angesehen. Und siehe da, es geht gar nicht darum alle Einsen zu zählen, sondern alle aufeinanderfolgenden Einsen. Das legt den Verdacht nahe, daß der riesengroße Aufwand nur in einer völlig falschen Aufgabenteilung fußt. Warscheinlich wird ein Signal abgetastet, d.h. die Information (Impulslänge) liegt schon seriell vor. Und da ist es doch am allereinfachsten eine Zähler mitlaufen zu lassen, der bei einer 0 immer resettet wird. Das ganze reduziert sich also auf schlappe 8 FFs und die werden bestimmt keine 500 LEs belegen. Wie man sieht, kann man Aufgaben auch ganz gewaltig aufblähen, ohne den allergeringsten Nutzwert. Peter
Peter das verstehst du aber komplett falsch, bzw. ich hätte dich da anders eingeschätzt. Es geht mir garnicht mehr um die Lösung des Eingangsproblemes sondern einzigst um den Lerneffekt. Deshalb hat FPGA-User ja auch einen separaten Thread aufgemacht. Du programmierst doch auch oder ? Warum programmierst du ? mal abgeshen davon das du so wie ich damit Brötchen verdienen möchtest. Ich für meinen Teil konnte mein Hobby mit meinem Beruf verbinden, und ich schätze mal das du sehr genau weist wie froh man manchmal als professioneller Entwickler ist wenn man seinen Spaß haben kann, richtig ? Aus meiner Sicht bedarf es also keines konkreten "Nährwertes", bzw. Lust und Spaß sind für mich ebenfalls eine Form eines "Nährwertes". >Warscheinlich wird ein Signal abgetastet, d.h. die Information >(Impulslänge) liegt schon seriell Jo könnte "wahscheinlich" sein, der Fragende hat aber im Ursprungsthread nichts weiter unternommen um dies genauer zu präzisieren. > Wie man sieht, kann man Aufgaben auch ganz gewaltig aufblähen, ohne > den allergeringsten Nutzwert. Zum Glück kann dies jeder für sich persönlich einschätzen und keiner ist verpflichtet die Meinung eines anderen in diesem Punkt zur eigenen machen zu müssen. Allerdings empfinde ich deine Worte als herablassend. Gruß Hagen
@Hagen "Allerdings empfinde ich deine Worte als herablassend." Dann hast du mich völlig mißverstanden. Es ist mir schon klar, daß es Dir darum ging: "wie helfe ich meinem Compiler/Fitter auf die Sprünge" Ich wollte nur klarstellen, daß dieses konkrete Problem kaum in der Praxis auftreten wird und wohl ein Resultat der falschen Problemanalyse ist. Auch wollte ich andeuten, daß es ein bischen schade um die Zeit ist, da sowas ja doch sehr compilerspezifisch ist, also kaum auf andere Probleme übertragbar. Ich hatte mal einen Coolrunner mit Webpack 3 designed und dann auf Webpack 4 geupdatet. Das Resultat war, der Fitter konnte es nicht mehr fitten. Eigentlich hätte man doch von einer neuen Version Verbesserungen erwarten sollen. Ich hab dann das Sourcefile an Xilinx geschickt und die haben es nach einer Weile geschafft. Der Hack war aber dermaßen brutal, daß nie im Leben einer auf sowas kommen kann. Die haben bestimmt Tage dran gesessen und Internas über den Chip im Kopf, die in keinem Datenblatt stehen. Zu allem Übel hat Webpack 4 die 3-er völlig zerstört, aber ich hatte glücklicher Weise noch die Installdateien. Eine Parallelinstallation ist nicht möglich, ich benutze die 3-er heute noch. Mit FPGAs habe ich noch nichts gemacht, ich bin das Denken in Macrozellen noch vom alten 22V10 gewöhnt. Auch ist mir suspekt, daß FPGAs erst über einen EEPROM geladen werden müssen, d.h. nicht sofort nach dem Einschalten funktionieren. Meine CPU würde auch ziemlich dumm aus der Wäsche gucken, wenn nach dem Einschalten der Adreßdekoder nicht sofort funktioniert. Und auch die Peripherie darf nicht erst ne Weile lustig in der Gegend rumfloaten, sondern muß sofort die richtigen High- und Lowpegel kriegen. Auch ist es schön, daß die Coolrunner immmer volle Geschwindigkeit haben, da CMOS. D.h. ich muß nirgendwo zwischen Stromverbrauch und Geschwindigkeit optimieren. Peter
Hallo Peter >"Auch ist mir suspekt, daß FPGAs erst über einen EEPROM geladen werden müssen, d.h. nicht sofort nach dem Einschalten funktionieren." Dass ein FPGA einen PROM zum booten braucht ist nicht suspekt sondern logisch ;). Ein FPGA ist im Grunde genommen wie ein RAM aufgebaut. Und da ein RAM bekannterweise flüchtig ist, so ist dies auch der FPGA. D.h. bei Wegnahme der Versorgungsspannung verliert der FPGA seinen Inhalt. Wenn wieder Spannung angelegt wird muss der FPGA zuerst aus einem PROM booten um wieder funktionieren zu können.... es werden also alle im HDL Design vorgegebenen Verbindungen im FPGA wieder hergestellt, sodass dieser wieder die gewünschte Funktionalität erhält. Das mit dem RAM ist natürlich nur im allergröbsten Sinne so, wie ich es beschrieben habe.... Ich hoffe ich(als Hobbyelektroniker) konnte dir (als "Elektronikgott") weiterhelfen. ;) Gruß Daniel!
@Peter: > Auch wollte ich andeuten, daß es ein bischen schade um die Zeit ist, Jain. Zeit ist Geld da gebe ich dir Recht, aber anderseits sage ich mir immer das es im Grunde egal ist womit man seine 80 Jahre runterreißt, am Ende schaffen es sowieso nur 0.0000001% der Menschheit "unsterblich" zu werden. > da sowas ja doch sehr compilerspezifisch ist, also kaum auf andere > Probleme übertragbar. Nein sehe ich nicht so. Schaue dir mal mein VHDL genauer an, du als Profi wirst sofort erkennen das meine 32 BitCount Funktion eine 1 zu 1 Übersetzung einer cleveren C/PASCAL/Assembler Routine ist. Es hat mich also gereizt zu sehen ob ich diese auf PC's/MCU's übliche Routine in VHDL umgesetzt bekomme. Es ist doch so das man theoretisch eine Sprache "lernen" kann, zumindestens glauben das die Studenten an den Unis. Ich meine aber das man eine Sprache erst wirklich nutzen kann wenn man vorher kleinere praktische Probleme durch die Arme in die Hände und Finger ins Keyboard programmiert hat. Und VHDL hat ja nun teilweise eine wirklich "Fingerunfreundliche" Syntax. Nebenbei bemerkt: meine obige Idee, mit der komprimierten Darstellung der Zähler erzeugt ebenfalls 501 LE's !! FPGA-User hat also Recht behalten. Gelernt habe ich daraus das ich viel mehr der "Intelligenz" der Fitter vertrauen kann. Denn schaut man sich die verschiedenen VHDL Sourcen an so erkennt man das einige Vektoren viel größer sind als sie sein müssten, das man viel mehr temporäre Zwischensignale benutzen kann, und trotzdem wird das gleiche Ergebnis synthetisiert. In Zukunft werde ich mir also garantiert nicht mehr so viel Zeit nehmen um die Datenobjekte zu optimieren, stattdessen mehr auf abstraktere Datentypen wie Integer statt std_logic_vector() setzen. Einfach weil es keinen Unterschied zu machen scheint, der Source aber lesbarer und intuitiver wird. Ergo: meine Zeit habe ich nicht verschwendet. Gruß Hagen
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.