Forum: FPGA, VHDL & Co. FGPA SRAM Zugriff für CPU und VGA


von Damian (Gast)


Lesenswert?

Hallo Leute,

Ich steh ein bisschen am Berg, ich hoffe jemand kann mir aus der Patsche 
helfen.

Falls mein "Problem" keines ist, bitte ich schonmal um Entschuldigung. 
Als (bisher) reiner Software-Mensch bereitet mir die ganze 
FPGA-Geschichte einiges Kopfzerbrechen - und bis ein paar Wochen wusste 
ich nicht mal was VHDL ist.

Ich hab ein Cyclone II Board mit 50Mhz, LEDs, SRAM, Flash und VGA-Out 
etc. Einige grundsätzliche Dinge (LEDs/LCD/7Segment ansteuern, VGA-Sync) 
hab ich unterdessen kapiert, mit Verilog komm ich auch einigermassen 
zurecht. Wo ich aber hänge ist beim SRAM resp. RAM allgemein.

Unterdessen läuft auch meine erste 'CPU' (12Bit Adressen / 8Bit Daten)- 
die kann schon mal Speicherzellen lesen, schreiben, inkrementieren und 
JMPen. Die Daten holt er von einem normalen Single Port RAM (FGPA 
intern). Als "Debug-Out" benutze ich das Siebensegment-Display.

Die Kommunikation RAM <-> CPU ist im Moment so gelöst, dass ich jeweils 
die Ram-Adresse, via Programm-Counter im CPU, setze, dann im nächsten 
Takt das Ram auslese, verarbeite und wieder die nächste Adresse setze. 
In wieweit dieser Ablauf überhaupt sinnvoll ist, kann ich (noch) nicht 
beurteilen. Auf jeden Fall funktioniert es soweit gut.

Das (weit weit entfernte) "Endziel" ist ein kleiner Compi mit 16Bit CPU, 
ein paar KB ROM (FPGA-Intern), RAM (SRAM) und VGA-Ausgabe.

Jetzt zum eigentlichen Problem:
Ich möchte einen Teil des RAMs als Videospeicher benutzen und 
entsprechend über den VGA-Ausgang ausgeben.

Für mich grosses, grundsätzliches Problem: Ich kann ja nicht im 
VGA-Modul wieder die RAM-Adresse setzen und auslesen, weil ja die CPU 
gerade von einer anderen Adresse liest oder schreibt. Ein Dual-Port Ram 
kann ich soweit ich weiss nicht verwenden, da ich eigentlich das normale 
SRAM (4Mbit) auf dem Board verwenden will, und nicht den FPGA-Internen 
Speicher (hat nur knapp 20Kbyte).

Nach meiner Auffassung müsste ich jetzt den Bus 'teilen', dass jeweils 
abwechslungsweise CPU und VGA-Modul auf das Ram zugreifen können.

Hier ist die absolute Blockade, ich hab keinen Dunst wie ich das 
grundsätzlich am besten angehen soll, und konnte bis jetzt auch nichts 
online finden (was nicht heisst dass es nicht existiert natürlich). Ich 
geh mal davon aus, dass ich im ganzen Aufbau einen schrecklichen/doofen 
Denkfehler drin habe. Aber wo?

Hat jemand einen Denkanstoss/Lösungsansatz?

Ach ja, ich benutze Quartus II / Verilog - wobei es mir nicht um den 
Code geht, sondern vor allem ums Verständnis.

Vielen Dank schon mal - und sorry für den langen Post - ich hoffe jedoch 
meine Unklarheiten verständlich ausgedrückt zu haben :)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Damian schrieb:
> Nach meiner Auffassung müsste ich jetzt den Bus 'teilen', dass jeweils
> abwechslungsweise CPU und VGA-Modul auf das Ram zugreifen können.
Du brauchst einen Verwalter, an den das RAM angebunden ist, und der vom 
VGA-Controller und von der CPU Speicheranfragen (lesen/schreiben) 
erhält.
Und dann mußt du die Anfragen irgendwie priorisieren und ans RAM 
durchreichen.

Du wirst sehen: allein die CPU war etwa 10% Arbeit, jetzt gehts erst 
richtig los... ;-)

von Rene B. (themason) Benutzerseite


Lesenswert?

@Damian

da vllt mal ein Lösungsvorschlag den ich auch schon etwas länger 
verfolge, aber bisher noch nicht weiter umgesetzt habe (zumindest nicht 
in der Variante wie es mir vorschwebt) :

Das ext. RAM wird von dem von Lothar erwähnten Verwalter angesprochen. 
Und zwar in der Form das du einerseits das Interface für deine CPU, 
andererseits aber das Interface für deine VGA-Grafik zur Verfügung 
stellst.
Meine Idee ist dahingehend das der Verwalter auch tlw die VGA 
Generierung übernimmt. Und zwar in der Form das der VGA-Teil immer 4,8 
oder 16 Pixel vorgesetzt bekommt, und der Verwalter in der Zwischenzeit 
einen oder mehrere Zugriffe der CPU übernimmt. Schematisch sieht das 
ganze etwa so aus :

|---------|-------|----> t
|8 pixel  |1/2 Zug|
|für VGA  |riff fü|
|         |r CPU  |

Sprich, der Verwalter lässt deine CPU warten solange bis er ein 4,8,16 
Pixel Paket eingelesen hat und die VGA-Grafik "ruhe" gibt und somit dann 
die CPU bedient werden kann. Das ganze macht deine CPU natürlich 
deutlich langsamer, aber es wäre ein Weg. Es gibt sicherlich noch einige 
andere Wege. Aber das wäre erstmal einer der denke ich halbwegs schnell 
umgesetzt werden kann.
Aber ich als non-FPGA-Experte überlasse lieber denen das Wort die auch 
Ahnung davon haben.

Im übrigen : Schönes Projekt. Habe mir selbst gerade erst meine erste 
16bit CPU gebastelt. Habe auch schon VGA, allerdings nur Text, reicht 
auch erstmal, der 200'er Spartan macht schon dicke Backen :-)

von Damian (Gast)


Lesenswert?

Danke Lothar und Rene :)

Ein paar Lichter sind aufgegangen! Aber so ganz hell ist es noch 
nicht...

Folgende Ueberlegung:

Ich beschränke meinen VGA-Output auf 1Bit - dann kann ich in einem 
"Rutsch" 8 Pixel (=8 Bit) aus dem Ram lesen. Wenn alle Komponenten mit 
25Mhz laufen, muss somit der VGA-Teil während einem Takt lesend, die CPU 
während den nächsten 7 Takten lesend und schreibend auf das Ram 
zugreifen können.

Den Priorität würd ich über ein "Bus Active" Signal vom Ram-Verwalter 
gegeben. Wenn Bus Active auf low geht, darf die CPU das Ram verwenden, 
sonst der VGA-Teil. Im Ram-Verwalter würd somit ein einfacher Counter 
von 0-7 bei jedem Takt hochgezählt. Bei Counter = 0 ist Bus Active High, 
sonst Bus Active Low.

Würde sowas grundsätzlich Sinn machen? Oder wär umgekehrt (nicht ein "du 
darfst"-Signal vom Verwalter schicken, sondern ein "ich muss" vom Modul 
erhalten) besser?

von Rene B. (themason) Benutzerseite


Lesenswert?

Ich bin da zwar auch nicht sooo fit drin aber grundsätzlich würde ich 
erstmal sagen das das so klappt. Also das du für den Teil der Zeit (ich 
nenn es mal VGA-Zeit) die CPU pausierst, bzw Zugriffe auf den Speicher 
warten lässt und während der anderen 7 Takte die CPU laufen lässt.
Du mußt dir nur überlegen (und da hakt es bei mir ab und an noch) das du 
mehr als 1 Takt für einen Lese/Schreibzugriff brauchst, bzw die 
Setup/Hold-zeit u.u. mehr als 1 Takt beträgt. Du musst ja auch beim 
wechseln zwischen Schreiben und Lesen den Datenbus erst inaktiv schalten 
bevor du ein Output Enable setzen kannst das das RAM die Daten 
ausspuckt. Da brauchst du mindestens schonmal einen Takt. Dumm ist dann 
nur wenn deine CPU schreiben will, und gerade wenn alles angelegt worden 
ist dann der VGA-Teil seinen Platz haben will. Daher mach ich das so das 
der Verwalter immer nur Zugriffe komplett macht und auch abgeschlossen 
hat, und somit der Verwalter das Grundlegende Timing bestimmt. Nur hat 
man dann andere Probleme ...
Aber ich würde mal sagen ab hier ist Lothar eher der Ansprechpartner. So 
tief steck ich in VHDL auch nicht drin, bzw ich mach es mir immer etwas 
einfach und umschiffe Probleme meist durch Inkaufnahme mehrerer Takte. 
Bin also das was man nen Hobby-FPGA'ler nennt :-))

von Damian (Gast)


Lesenswert?

Warum murmle ich immer "Dieser Weg wird kein leicher sein" vor mich hin? 
Egal.

Mein aktueller Stand (theoretisch erstmal, im praktischen happerts noch 
ein wenig):

Wie gehabt möchte ich 7 Zyklen der CPU, einen dem VGA-Teil geben. Mein 
Board läuft mit 50Mhz, das SRam hat 20ns Zugriff.

"VGAS": (VGA Sync) Ich teil den Takt auf 25Mhz und schreib jeweils ein 
Bit raus (Daten ab Buffer, siehe "VGA") - dieses Modul funktioniert auch 
schon.

"VGA": Im Takt "E" wird die Ram-Adresse und Read gesetzt, im Takt "F" 
wird der Buffer mit 1 Byte gefüllt.

"CPU": Setzt jeweils in den geraden Takten die Ram-Adresse und R/W, 
damit die Daten dann bei bei ungeraden Takten zur Verfügung stehen resp. 
geschrieben werden können - ausser im Takt E und F

"ADS" = "Address Set" (+ R/W etc.)

TAKT  VGAS   VGA  CPU    TAKT
0     VW0         ADS
1                 CPU    CPU1
2     VW1         ADS
3                 CPU    CPU2
4     VW2         ADS
5                 CPU    CPU3
6     VW3         ADS
7                 CPU    CPU4
8     VW4         ADS
9                 CPU    CPU5
A     VW5         ADS
B                 CPU    CPU6
C     VW6         ADS
D                 CPU    CPU7
E     VW7   ADS
F           VGA          VGA1


Somit hätte ich, in meiner Vorstellung zumindest, eine CPU, die mit 
25/8*7 = ~22Mhz läuft, und könnte einen Ram-Bereich als VGA-Output 
(1Bit/Pixel) benutzen - super!

Könnte das hinhauen oder bin ich wiedermal auf dem Holzweg? V.a. die 
Zugriffszeit auf das SRam (20ns).. könnte die zum Verhängnis werden?

von Dimi (Gast)


Lesenswert?

Hallo,

früher hatte ich selbe Problem. Ich habe T80 (Z80 Softcore) verwendet.
Meine erste lösung war:
Speicher lief mit 4-fache CPU-Frequenz. Das heisst, ich hatte mit jedem 
CPU-Takt zwei Speicherzugriffe. So hat es auch gut funktioniert.
Dann habe ich meinen "Speicherkontroller" bisschen "intelligenter" 
gemacht:
Z80 hat viele "Nicht-Speicherzugriff"-Zyklen (z.B. Refresh u.s.w.). In 
der Zeit holt mein Videokontroller die Daten aus dem Speicher.

MfG aus Westerwald

von dasrotemopped (Gast)


Lesenswert?

um das Rad nicht neu erfinden zu müssen, bei Quartus II Web Edition 
steht unter den Megafunctions im Bereich Storage auch Dual Port RAM 
Controller zur Verfügung. Da der VGA Controller nur liest und 
Timinggenau sein muss und die CPU R/W Zugriffe machen muss aber ruhig 
mal warten kann gibt es da vielleicht schon eine schlüsselfertige 
Lösung. uC im FPGA mit VGA Controller ist schon dutzende Male gelöst 
worden und wird in den gängigen FPGA Tools als Bausteine für diverse 
Plattformen und Bitbreiten angeboten. Da meist "quelloffen" auch nett um 
das Verständnis zu fördern. Wenn mit Wishbone Interface auch sehr 
recyclefähig.

Gruß,

dasrotemopped.

von faul (Gast)


Lesenswert?

Hi,

fertige Lösungen sind natürlich Gold wert, aber nur was man selber 
gemacht hat kann man auch gut selber debuggen...

Diese Zugriffssteuerung fürs RAM ist auch bekannt als Arbiter, oder 
Bus-Arbiter. Da gibt es sicherlich für verschiedene CPU-Busse auch schon 
fertige Lösungen.
Es gibt wie du schon gemerkt hast auch viele Wege so eine 
Zugriffssteuerung umzusetzen.

Du musst z.B. den Zugriff auch nicht mit einem festen zeitlichen Raster 
umsetzen, du könntest auch bei dem Arbiter mehrere Anforderungssignale 
definieren. Jeder Busteilnehmer kann dann über das Anforderungssignal 
den (Ram-)Bus anfordern und bekommt über ein Grant-Signal dann Bescheid, 
wenn er den Bus hat. Wenn der Bus nicht mehr benötigt wird, muss das 
Anforderungssignal natürlich wieder zurückgenommen werden.

Solche Themen sollten sich über Google auch unter dem Thema 
"Handshaking" oder "Handshake" finden lassen.

Allgemein für CPU-Design kannst du dir folgendes Buch durchlesen (von 
allem ein bisschen und auch recht tiefgehend):

http://www.amazon.com/Computer-Architecture-Quantitative-Approach-4th/dp/0123704901

Vielleicht gibts da inzwischen auch ne neue Edition...

von Damian (Gast)


Lesenswert?

Vielen Dank für die vielen Inputs!

Ich bin mal den einfachsten Weg gegangen - Fixe Zuordnung 3 Takte CPU - 
1 Takt VGA - und es läuft!

Mit 7 Takten CPU / 1 Takt VGA hängte sich das ganze noch auf, mit der 
Halbierung der Zugriffe klappt jetzt alles wunderbar.

Jetzt hab ich mal die Basis, um meine CPU mit Befehlen zu erweitern und 
auch einfache Grafiken darzustellen.

Im nächsten Schritt folgt dann die Umschaltung vom internen FPGA-Ram auf 
den SRAM-Baustein und benutzung des FGPA-Rams als ROM-Bereich.

Vielen Dank nochmals für die Wegweisung :) Sobald ich was einigermassen 
zeigbares zusammen habe, werd ich es hier posten.

von Rene B. (themason) Benutzerseite


Lesenswert?

>Im nächsten Schritt folgt dann die Umschaltung vom internen FPGA-Ram auf
>den SRAM-Baustein und benutzung des FGPA-Rams als ROM-Bereich.

Soweit bin ich mit meinem Design auch gerade. Aber der Bootloader zickt 
noch rum und ich habe gerade keine Ahnung wo der Fehler sein könnte. Na 
ja. Aufgeschoben ist nicht aufgehoben. Evtl poste ich mein Design hier 
auch. Vor allem weils so schön auf ein Spartan 3 200 Board passt :-)

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.