Hallo zusammen,
In meinem Design habe ich mehrere Module, welche über einen Satz von
8/16/32 Bit Registern gesteuert werden.
Diese Registerblöcke bilden alle Steuer- und Statusleitungen der
nachgeschalteten Logik ab, so dass über die uC-Zugriffe auf die Register
der Ablauf gesteuert werden kann.
Intern sind die einzelnen Registerblöcke über einen 32Bit
bidirektionalen Datenbus mit der uC-Zugriffslogik verbunden, der Zugriff
auf die Blöcke wird über diese Kontrollsignale erledigt:
1
-- Steuerung Lese/Schreibvorgang auf den Registern
2
INT_REG_A:inSTD_LOGIC_VECTOR(7downto2);
3
INT_D:inoutSTD_LOGIC_VECTOR(31downto0);
4
INT_CYCLE_access:inSTD_LOGIC;
5
INT_CYCLE_dir:inSTD_LOGIC;
6
INT_CYCLE_WRITE_ACCESS_impuls:inSTD_LOGIC;
INT_REG_A : adressiert block-intern das gewünschte Register
INT_D : bidirektionaler Datenbus
INT_CYCLE_access : ist aktiv, wenn dieser Block adressiert wurde
INT_CYCLE_dir : 0=read, 1=write Zyklus
INT_CYCLE_WRITE_ACCESS_impuls : Impuls zur Übernahme der Schreibdaten
Soweit, so schlecht ;-)
Der bidirektionale Datenbus ist sicher noch ein Problem, das werde ich
noch anpacken.
Meine Frage zielt nun mehr darauf ab, wie solche Register effizient
implementiert werden können.
Das Lesen der Register wird in einem kombinatorischen process erledigt,
wo direkt auf INT_D() ausgegeben wird, falls die richtige Stelle
adressiert ist:
Für das Lesen des Registers wird im kombinatorischen process das Signal
COUNTER_CONTROL_REG_write gesetzt, so dass im separaten Prozess der
Register Inhalt übernommen werden kann:
Funktionieren tun die Register einwandfrei, ich habe nur den dringenden
Verdacht, dass sich das Ganze einfacher beschreiben liesse.
Auf das Problem aufmerksam geworden bin ich u.a. durch die in diesem
Thread gezeigten Logik-Kaskaden:
Beitrag "View RTL Schematic: "falsche" Darstellung des Designs"
Richtig lustig wird es dann, wenn nicht wie hier nur 8 sonder 16
Register implementiert werden.
Frage:
- Wie implementiert ihr eure Register im FPGA? Ähnlich wie ich oder
komplett anders?
Anschlussfrage: Wie entferne ich den bidirektionalen Bus am besten?
INT_D in INT_D_in und INT_D_out auftrennen und von INT_D_in lesen ist ja
noch kein Problem.
Schreiben auf INT_D_out ist nun aber immer noch problematisch. Der Bus
ist zwar nicht mehr bidirektional, für die Beschreibung brauche ich aber
trotzdem einen Tristate Output. Sehe ich das falsch? Oder wie wird so
etwas direkt mit MUX beschrieben?
Hmm, meine Registerbank gibts nur FPGA intern und geht nicht direkt an
die Ausgänge, darum kann ich diesbezüglich nichts raten.
Mir ist dein Tristate-Output nicht ganz geheuer. Funktioniert das schon
in HW oder noch nur in der Simulation. Es kommt mir so vor als würden
bei dem Code so wie er dasteht die Ports von uC und FPGA gegeneinander
treiben, zumindest in dem kurzen Zeitfenster wo der uC einen Lesevorgang
auslöst und der FPGA kombinatorisch den Ausgang setzt.
Ich glaube auch, dass es nicht gut ist, die Register ohne FFs
(insbesondere Output FFs) dazwischen zu schalten, auf die Ausgänge zu
legen.
Insofern wäre mein Tipp: Behalte deinen bidirektionalen Port aber schau
dir an, wie man den auf dem FPGA, das du verwendest, ansteuern soll und
implementier das, wobei die Registerdaten noch in Output FFs gepuffert
werden. Dann sollte auch das Timing kein Problem machen, wenns mal
größer wird.
Die gepostete Beschreibung deutet eigentlich nicht auf eine derart tiefe
Verschachtelung hin...
Das müssten ziemlich viele "if..elsif...elsif..." sein :-/
Auch eine concurrent-Zuweisung mit vielen "else ... when" kann sowas
ergeben. Aber wie gesagt, das kann aus diesem Codefragment noch nicht
erkannt werden...
Was sind die Signale, die in diese Gatterkette hineingehen? Kommen die
aus dem INT_REG_A(7..2)?
Matthias F. schrieb:
> Hmm, meine Registerbank gibts nur FPGA intern und geht nicht direkt an> die Ausgänge, darum kann ich diesbezüglich nichts raten.
Da habe ich mich wohl nicht klar ausgedrückt.
Das oben gezeigte Modul ist eines von mehreren Register-Modulen. Diese
(insgesamt 11) Module habe einen eigenen Adressbereich im external
Memory des uC und werden über eine im FPGA implementierte Zugriffslogik
angesteuert.
> Mir ist dein Tristate-Output nicht ganz geheuer. Funktioniert das schon> in HW oder noch nur in der Simulation.
Ja, das funktioniert in Hardware synchron am uC mit einem 48MHz Clock.
> Es kommt mir so vor als würden
Die (nicht gezeigte) Zugriffslogik regelt das.
> Insofern wäre mein Tipp: Behalte deinen bidirektionalen Port aber...
Zu spät ;-) Ich bin nun daran, den bidirektionalen Bus auf einen
separaten D_IN und D_OUT Bus umzuschreiben - Aufwand hält sich in engen
Grenzen.
Auszug aus dem neuen COUNTERRegister.vhd:
Das Tristate Problem ist nun aber trotzdem noch nicht gelöst: Jedes
meiner 11 Module hat nun einen D_OUT Bus, welcher auf die Interface
Logik schreiben will.
Wie werde ich den Tristate da jetzt auch noch los?
Zum Problem mit den vielen hintereinandergeschalteten Gattern:
(siehe hier: Beitrag "Re: View RTL Schematic: "falsche" Darstellung des Designs")
Das kam daher, dass im kombinatorischen für alle Bits von INT_D ein 'Z'
als Defaultwert zugewiesen wurde. Sobald ich den Defaultwert auf '0'
ändere wird die Zuordnungslogik wesentlich breiter und weniger tief. Die
Anzahl der verwendeten Gatter ändert sich aber nur unwesentlich.
Die "neue" RTL Darstellung ist im Anhang gezeigt.
Nun zu dir, Lothar...
Lothar Miller schrieb:
> Die gepostete Beschreibung deutet eigentlich nicht auf eine derart tiefe> Verschachtelung hin...
Siehe oben. Es hing wohl davon ab, dass im case nicht jedes Mal die
ganzen 32 Bit geschrieben wurden. Somit wurden die einzelnen Bits von
INT_D unterschiedlich behandelt (bei der Gatter-Kaskade handelte es sich
übrigens um die Zuweisung auf INT_D(0).
> Das müssten ziemlich viele "if..elsif...elsif..." sein :-/> Auch eine concurrent-Zuweisung mit vielen "else ... when" kann sowas> ergeben.> Aber wie gesagt, das kann aus diesem Codefragment noch nicht> erkannt werden...
ganzes File im Anhang reichte nicht? Müsste auch die komplette uC
Interface Logik dazu?
> Was sind die Signale, die in diese Gatterkette hineingehen? Kommen die> aus dem INT_REG_A(7..2)?
Das INT_REG_A() enthält direkt die 32Bit uC Adressen.
INT_CYCLE_access wiederum ist nur dann aktiv, wenn über die höheren uC
Adressen der richtige Adressblock ausgewählt ist. Beide Signale sind
abgeclockt. Da sollte es eigentlich nicht Probleme geben.
Ich werde den uC Interface Teil in den nächsten Beiträge trotzdem kurz
erläutern.
INT_REG_A(7 downto 2) ist nichts anderes als eine direkte, abgeclockte
Zuweisung des Teilvektors uC_ADDR(15 downto 0) -> uC Adresse
INT_CYCLE_dir hängt ziemlich direkt am /RD, /CS und /OE des uC:
und noch der Write Impuls:
dieser wird aus dem /WR des uC generiert, jeweils nur dann, wenn ein
Zugriff auf einen gültigen Block erfolgte und nur auf die 32Bit Adressen
1
-- Write Zugriff, Daten aus 32Bit Interface Register in Register der Module uebernehmen
Nochmals zur Gatter-Kaskade:
Wahrscheinlich realisiert XST hier nicht, dass es sich bei den
Zuweisungen auf INT_D_OUT eigentlich um einen 32Bit n-zu-1 MUX handelt,
bei welchem halt nicht jedesmal alle Bits geschrieben werden.
Würde es wohl Ressourcen sparen, diesen MUX explizit als solchen zu
formulieren, d.h. die Zuweisungen auf INT_D_OUT separat zu erledigen und
nebenläufig die Write-Impulse zu generieren?
Oder sollte das ganze zur Ressourcenoptimierung in einen synchronen
process reingepackt werden?
Hallo Martin,
ich habe ein ähnlichen Aufbau in meinem Design (mehrere Sub-Einheiten
mit eigenen Registerbänken).
Ich benutze einen geteilten Datenbus INT_D_in, INT_D_out wobei alle
Ausgänge über ein großes Oder-Gatter zusammengeschaltet sind. Das
bedingt natürlich, daß immer nur eine 'Einheit' selektiert ist und die
anderern im nicht-selektierten Zustand einen Null-Vektor auf ihren
Ausgang legen.
In Vhdl sieht das dann etwa so aus:
Die Tristate-Leitungen sind das Ausgänge über die I/O Bank, oder handelt
es sich um interne Signale?
Die Spartan3 haben noch echte interne Tristate-Buffer,
Spartan3A und 3E kennen so etwas nicht mehr - hier wird tristate über
Logik abgebildet :-///.
> Die Spartan3 haben noch echte interne Tristate-Buffer
Wo im DB steht das?
Spartan II hatten noch TBUF,
ab S3 wurden solche Busse von Multiplexern abgelöst
Bernd Geyer schrieb:
> Hallo Martin,>> ich habe ein ähnlichen Aufbau in meinem Design (mehrere Sub-Einheiten> mit eigenen Registerbänken).>> Ich benutze einen geteilten Datenbus INT_D_in, INT_D_out wobei alle> Ausgänge über ein großes Oder-Gatter zusammengeschaltet sind. Das> bedingt natürlich, daß immer nur eine 'Einheit' selektiert ist und die> anderern im nicht-selektierten Zustand einen Null-Vektor auf ihren> Ausgang legen.
Genau so machen wir das auch. Lebare Register per "Chip-Select" aus
einem 6 zu 64 One Hot Decoder legen ihre Daten wenn sie selektiert sind
auf den Ausgang des Moduls, im Top-Level sind die einfach alle
Oder-verfknüpft. Funktioniert sehr gut. Der One-Hot-Decoder wird vom XST
Slice-sparend in den BlockRam als ROM abgebildet (wenn Block RAM
verfügbar).