Autor Thema: Logisim CPU  (Gelesen 160033 mal)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #220 am: 04. June 2013, 01:18 »
Hallo,

wenn ich mir deine Konzepte so anschaue, frage ich mich ehrlich gesagt, was du eigentlich erreichen möchtest. Du fügst ununterbrochen Features hinzu. Damit verlangsamst du nicht nur die CPU in der Simulation (was sie immer nutzloser macht), sondern du schaffst dir auch noch Dutzende Fehlerquellen, die dir später das Debuggen zur Hölle machen. Real implementieren willst du die CPU auch nicht. Dafür schielst du irgendwie immer auf x86, was definitiv kein besonders gutes Vorbild ist.

Wenn du so weitermachst, wirst du vor 2035 jedenfalls nicht fertig.

Gruß,
Svenska

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #221 am: 04. June 2013, 11:53 »
So lange er nicht die Probleme von x86 mitnimmt (A20 lässt grüßen) kann er von mir aus gerne darauf schielen, denn letztenendlich funktionieren doch alle Architekturen die so im Umlauf sind irgendwie doch alle gleich (vllt. vom eigendlichen Kern mal abgesehen). Sie haben alle einen Cache und TLB und ob ich dann CISC (x86) oder RISC (ARM, x86_64 ist dann son Mischmasch) oder VLIW (Itanium) habe ist dann denke ich mal auch egal.

Wie viel Dein Simulator aushält ist dann die andere Frage, ich hab zwar nicht den kompletten Beitrag gelesen aber es wäre vllt. besser wenn man erst einmal nur den Kern debuggt und sich erst danach an Caches und dergleichen wagt.

Gruß,
Streetrunner

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #222 am: 12. June 2013, 18:58 »
Zitat
Real implementieren willst du die CPU auch nicht.
Doch eigentlich schon, wenn ich mir mal ein FGPA-Board kaufe...

Zitat
Dafür schielst du irgendwie immer auf x86, was definitiv kein besonders gutes Vorbild ist.
Naja X86 ist nicht mein Vorbild (eher arm oder atmel). Ich schau glaub einfach zu oft im wiki nach wo meistens die x86 lösung beschrieben ist...

Zitat
Damit verlangsamst du nicht nur die CPU in der Simulation (was sie immer nutzloser macht), sondern du schaffst dir auch noch Dutzende Fehlerquellen, die dir später das Debuggen zur Hölle machen.
MMh man debuggt normalerweiße ganz am schluss wenn alles fertig gebaut ist ?  :-o Ich debugge eigentlich immer dann wenn ich wieder was dazugebaut habe(schaue dann ob alles passt und so funktioniert wie ichs mir vorgestellt habe und danach bau ich das nächste Element dazu und debugge wieder)




Zitat
aber es wäre vllt. besser wenn man erst einmal nur den Kern debuggt und sich erst danach an Caches und dergleichen wagt.
Naja mein Kern von der CPU ist ja schon fast fertig, es fehlt eben nur der Interrupt controller und ein paar Befehle sind noch nicht implementiert. Hier mal ein Foto von dem Kern(habs ein wenig skalliert, und wie kann man hier im Forum ein Spoiler machen?):




Nun zu meiner MMU, will ne besonderst einfache mmu bauen mit nur einer Pages-Größe und einfache Zugriffsrechte. Auserdem will ich die MMU als CO-Prozessor bauen ähnlich wie bei arm. Nun was soll ich noch so beachten bei der planung meiner MMU? Was sollte sie noch können?

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #223 am: 12. June 2013, 20:49 »
Naja, ich glaube eine "einfache" MMU gibt es nicht, denn ein paar grundlegende Dinge sollte jede MMU können:
Deine MMU sollte man Ein/Ausschalten können denn sonst wird es Probleme beim booten deines OS geben. Desweiteren muss sie auf den Speicher zugreifen können um die passenden Tabellen zu laden, dabei ist zu beachten dass die MMU der CPU evtl. den Busmaster "klauen" muss (Speicherzugriff auf eine Seite die nicht im TLB ist). Dann brauchst du noch eine Logik die deine Flags prüft (welcher Ring, lesen/schreiben, ...) und bei Bedarf einen Interrupt sendet. Als Ablauf dürfte dass dann so aussehen:

Die CPU gibt die gewünschte Adresse auf den Bus, welcher direkt in die MMU führt. Dort wird geprüft, ob die entsprechende Page bereits im TLB vorhanden ist (solltest du keinen TLB haben entfällt dieser Schritt). Ist die Page vorhanden so gibt man einfach den Inhalt des TLB-Eintrags auf den Adressbus und jut is. Sollte man keinen Treffer erziehlen so teilt man die Adresse der CPU in den Eintrag für das PD, den Eintrag für die PT und den Offset auf. Dann lädt man den Wert (Adresse vom PD) + (Offset im PD) in ein Register, und prüft ob der Eintrag dem man gerade geladen hat gültig ist und natürlich auch alle Flags. Dafür muss die CPU der MMU mitteilen was sie macht, d. h. ob sie schreiben oder lesen will, in welchen Ring der Task gerade ausgeführt wird, ...). Erhält man da Unstimmigkeiten so wird ein Interrupt ausgelöst. Passt alles, so ermittelt man aus dem geladenen Eintrag die Adresse der PT, und das ganze Spiel mit laden des Eintrags und checken usw. geht noch mal los. Passt dann immer noch alles so kann man aus dem geladenen Eintrag der PT und dem Offset der Adresse der CPU die gewünschte Speicheradresse bilden und auf den Adressbus legen. Dann sollte man der CPU evtl. noch mitteilen dass die MMU fertig ist und sie den Speicher anweisen kann Daten zu liefern oder entgegenzunehmen. Ich denke mal dass sich das sehr gut und einfach umsetzten lässt, auch größere Pages sind nicht schwer zu realisieren, man muss nur nach dem ersten "Laden und Checken" direkt zu "Gebe fertige Adresse aus" springen. Hardwaremäßig lässt sich das bestimmt wie eine Pipeline organisieren, also einfach hintereinander weg. Wenn du die MMU ausschaltest kannst du dann einfach die Adressen der CPU "drumherrum" direkt auf den Adressbus leiten.

Gruß,
Streetrunner

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #224 am: 13. June 2013, 02:10 »
Hallo,

Zitat
Real implementieren willst du die CPU auch nicht.
Doch eigentlich schon, wenn ich mir mal ein FGPA-Board kaufe...
Dann willst du aber lieber einen kleinen Kern (mit bekannten Einschränkungen), der auch in einen kleinen FPGA passt und dort schnell ist. Außerdem wirst du dich dann mit realen Timingbeschränkungen rumprügeln müssen, weil FPGAs nicht genug RAM haben.

MMh man debuggt normalerweiße ganz am schluss wenn alles fertig gebaut ist ?  :-o
Tests der Einzelteile ersetzen nicht den Test des Gesamtsystems. Wenn du später etwas am System ändern willst (z.B. wenn du das Betriebssystem schreibst und dir auffällt, dass du etwas wesentlich eleganter hättest lösen können), musst du das Gesamtsystem debuggen, nicht mehr die Einzelteile.

Im einfachsten Fall sitzt die MMU zwischen CPU und RAM und trennt den Speicher vollständig(!) vom normalen Bus ab. Das heißt, dass die CPU die gleichen Adressen sieht wie jedes andere Gerät auch. Die MMU ist in dem Falle gleichzeitig RAM-Controller, was den Vorteil hat, dass du die MMU für ihre eigenen Tabellen jederzeit Zugriff auf den Speicher hat und du dich an der Stelle nicht um Busarbitrierung kümmern musst. Weil die MMU extern ist, wird sie auch wie jede andere Hardware angesprochen, d.h. du brauchst keinen MMU-spezifischen Privilegierungsmechanismus mehr. Außerdem kannst du mehr Speicher anschließen, als du logischen Adressraum in der CPU verfügbar hast. Das macht natürlich Taskwechsel aufwändiger, weil du die MMU jedesmal neu konfigurieren musst. Deine Resetschaltung muss die MMU in einen definierten Zustand (z.B. 1:1-Mapping) bringen, damit du das System starten kannst und du kannst keine feinen Berechtigungen ({Kernel,User}{read,write,execute}-Niveau) machen, weil die MMU nur "read" und "write" auf dem Bus sieht. Dein Bus muss in der Lage sein, beliebig langsam auf Anfragen antworten zu können und Busmastering wird sehr schwierig.

Alternativ ist die MMU ein Teil der CPU, d.h. sämtliche Hardware außer der CPU selbst arbeitet mit physischen Adressen. Das ist der Weg, der heutzutage gegangen wird.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #225 am: 13. June 2013, 10:13 »
Alternativ ist die MMU ein Teil der CPU, d.h. sämtliche Hardware außer der CPU selbst arbeitet mit physischen Adressen. Das ist der Weg, der heutzutage gegangen wird.
Nein, heutzutage hat jedes Gerät sein eigenes Mapping. Man nennt es IOMMU. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #226 am: 13. June 2013, 10:27 »
Ok. Kann mein Computer noch nicht, darum habe ich mich damit nicht befasst. ;-)

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #227 am: 13. June 2013, 20:01 »
Zitat
Dann willst du aber lieber einen kleinen Kern (mit bekannten Einschränkungen), der auch in einen kleinen FPGA passt und dort schnell ist. Außerdem wirst du dich dann mit realen Timingbeschränkungen rumprügeln müssen, weil FPGAs nicht genug RAM haben.
Mhh was heist das genau? wie klein sollte den der kern sein?  Und was sind das für Einschränkungen?

Zitat
Tests der Einzelteile ersetzen nicht den Test des Gesamtsystems. Wenn du später etwas am System ändern willst (z.B. wenn du das Betriebssystem schreibst und dir auffällt, dass du etwas wesentlich eleganter hättest lösen können), musst du das Gesamtsystem debuggen, nicht mehr die Einzelteile.
Mhh stimmt, das wird schwierig wenn ich meine CPU zu kompliziert mache.

Zitat
Alternativ ist die MMU ein Teil der CPU, d.h. sämtliche Hardware außer der CPU selbst arbeitet mit physischen Adressen. Das ist der Weg, der heutzutage gegangen wird.
Naja so hatte ich das eigentlich vor :D

Mal was anderes, braucht man eigentlich überhaupt ne mmu um ein multitasking-os laufen zu lassen ?  :roll:


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #228 am: 13. June 2013, 20:13 »
Mal was anderes, braucht man eigentlich überhaupt ne mmu um ein multitasking-os laufen zu lassen ?  :roll:

Brauchen tut man es nicht. Aber du kannst dir ja mal überlegen welche Vorteile eine MMU haben würde.
Dieser Text wird unter jedem Beitrag angezeigt.

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #229 am: 13. June 2013, 22:07 »
Lies Dir dazu mal die Tutorials hier auf der Seite durch (OS-Dev für Einsteiger), da wird die MMU zu Beginn auch nicht benutzt und da steht auch drin was man machen muss um Multitasking ohne MMU zu implementieren.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #230 am: 24. June 2013, 20:35 »
Zitat
Lies Dir dazu mal die Tutorials hier auf der Seite durch (OS-Dev für Einsteiger), da wird die MMU zu Beginn auch nicht benutzt und da steht auch drin was man machen muss um Multitasking ohne MMU zu implementieren.
Wow sieht interessant aus.

Nun ich werd jetzt wohl das Konzept der Mips-MMU übernehmen, mit nem TLB mit 32 einträge. Die größten Probleme habe ich noch mit der Verdrängungs-taktik welche eignet sich den am besten für eine einfache TLB-Cache ?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #231 am: 24. June 2013, 21:56 »
Das ist doch dann sowieso das Problem der Software, oder? Ich denke, ich würde für den Anfang ein simples LRU machen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #232 am: 24. June 2013, 22:36 »
Zitat
Das ist doch dann sowieso das Problem der Software, oder?
Das kommt drauf an ob der TLB direkt beschreibbar ist oder nicht. Bei den meisten Architekturen geht das überhaupt nicht, die einzige Ausnahme stellt glaube ich Itanium, wo zumindest der L2-TLB von der Software aus beschrieben werden kann. Natürlich wäre es eine Idee, auch den L1-TLB beschreibbar zu gestalten. Das wäre vermutlich die einfachste Art einen TLB zu implementieren. Aber ob es auch die beste ist glaube ich nicht, da die Software zwar einen Überblick über die benötigten Seiten hat, allerding nichts davon weiß wie oft diese Seiten verwendet werden.

Zitat
ich würde für den Anfang ein simples LRU machen
Habe lange nachgedacht was LRU bedeuten könnte, aber wenn ich so auf meine Tastatur gucke dann denke ich das Du LFU meintest??? Ich glaube das ist auch nicht das gelbe vom Ei, da man hier für jeden Eintrag sowohl die Zugriffe als auch die Zeit benötigt, welche er im Cache existiert. Am einfachsten dürfte ein FIFO sein, realisiert mit einer Art Ringspeicher, bei dem immer ein Eintrag neu beschrieben wird, falls ein bestimmter Eintrag nicht im Cache vorhanden ist. Beim nächsten Cache-Miss wird dann der nächste Eintrag überschrieben. Von der Performance her ist das ab und an auch nicht wirklich super, aber wesentlich einfacher zu implementieren.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #233 am: 24. June 2013, 22:46 »
Tulefix hat MIPS erwähnt, das meines Wissens einen reinen Software-TLB hat. (Was allerdings nur Hörensagen ist, ich habe die MIPS-MMU nie selber programmiert.)

LRU ist Least Recently Used, d.h. der Eintrag, der am längsten nicht mehr benutzt wurde, fliegt raus. Die Hardware müsste dazu natürlich eine Art Reihenfolge der Einträge aktuell halten, sonst fehlt der Software die Grundlage, auf der sie LRU machen könnte. (Wobei man es mit einem Accessed-Flag pro Eintrag vielleicht ausreichend annähern könnte.)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #234 am: 25. June 2013, 11:37 »
Ah, ok, und wieder um eine Abkürzung schlauer  :-D. Ich denke mal dass es für LRU am einfachsten wäre einen großen Zähler mitlaufen zu lassen, welcher startet wenn die CPU aktiviert wird, oder vielleicht wenn ein Taskwechsel stattfindet. Wenn man dann noch für jeden TLB-Eintrag ein Register vorsieht, in welchem man bei Zugriff auf den Eintrag den Inhalt des Zählers speichert, dann kann man bei einem Cache-Miss den kleinsten Wert in diesen Registern raussuchen und den dazu gehörigen Eintrag überschreiben.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #235 am: 25. June 2013, 11:44 »
Mit Overflows muss man wahrscheinlich noch ein bisschen aufpassen, aber wenn die Software dafür zuständig ist, den Zähler zu erhöhen, dann kann sie ja dafür sorgen, dass kurz bevor es knallt alles wieder auf die ersten paar natürlichen Zahlen zusammengestaucht wird.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #236 am: 07. July 2013, 22:45 »
Nun ich glaub der Svenska hat recht... ich hab versucht die MMU und die CPU in VHDL zu realisieren.
Und ihrgentwie ist mir Die CPU mit der MMU zu kompliziert, daher werd ich die MMU weglassen, die CPU greift direkt mit der physischen adresse auf den bus zu und ein Co-Prozesser prüft ob die CPU gerade berechtigt ist auf die adresse zuzugreifen..

Dazu besitzt der Co-Prozessor 4 registerpaare mit je 2 registern. Jeweils eines der register in einem Registerpaar, markiert der anfang eines Bereichs auf der die CPU zugreifen darf und das andere Register markiert das Ende dieses Bereiches.(also insgesamt kann man im Co-Prozessor 4 Bereiche makieren).

Auserdem kennt sich jemand mit vivado 2013.2 aus?Ich hab da ein Problem mit dem simulator, der öffnet sich zwar aber wenn ich versuche die simulation zu starten Kommt diese Fehlermeldung:
ERROR: [Simulator 45-1] A fatal run-time error was detected. Simulation cannot continue.
Hab schon alles versucht, nicht einmal bei den Projekt-Beispiele funktioniert der simulator.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #237 am: 10. July 2013, 21:19 »
Hallo,

irgendwie gefällt mir dein Ansatz mit den erlaubten Bereichen und dem Co-Prozessor nicht. Das klingt alles so kompliziert.

Eine MMU ist im einfachsten Fall ein SRAM. Bei jedem Speicherzugriff gehen die unteren 12 Bit der (physischen) Adresse an den Adressbus (ergibt 4 KB/Page) und die restlichen, oberen Bits an das SRAM der MMU. Das Datenwort, welches aus diesem SRAM kommt, nimmst du dann als die neuen (virtuellen) oberen Adressbits. Der Inhalt dieses SRAMs enthält dann dein Mapping und muss natürlich irgendwie vom Betriebssystem aus änderbar sein - und unterliegt damit wie jede andere Hardware auch dem Zugriffsschutz(*).

Wenn du im Betriebssystem dann noch vereinbarst, dass das oberste Bit der Einträge im SRAM eine ungültige Page markiert, dann kannst du mit der obersten Adressleitung der virtuellen Adresse direkt einen Page-Fault auslösen. (Wenn du die MMU aber gerade beschreibst, darfst du natürlich keinen Page Fault auslösen.)

(*) Wenn du für Hardware einen getrennten Adressraum vorsiehst, ist das recht einfach. IN/OUT dürfen nur im Kernelmodus verwendet werden, denn MMU und Hardware sind Aufgaben des Betriebssystems. READ/WRITE dürfen immer verwendet werden und wenn auf eine ungültige Adresse zugegriffen wird, löst die MMU nachträglich einen Page Fault aus.

Deinen Simulator kenne ich nicht.

Gruß,
Svenska

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #238 am: 12. July 2013, 23:58 »
Zitat
irgendwie gefällt mir dein Ansatz mit den erlaubten Bereichen und dem Co-Prozessor nicht. Das klingt alles so kompliziert.

Nun ok ich wollte eigentlich auch für die interruptbehandlung nen CO-prozessor einbauen(so ähnlich wie bei mips), soll ich den auch steichen?

Zitat
Eine MMU ist im einfachsten Fall ein SRAM. Bei jedem Speicherzugriff gehen die unteren 12 Bit der (physischen) Adresse an den Adressbus (ergibt 4 KB/Page) und die restlichen, oberen Bits an das SRAM der MMU. Das Datenwort, welches aus diesem SRAM kommt, nimmst du dann als die neuen (virtuellen) oberen Adressbits. Der Inhalt dieses SRAMs enthält dann dein Mapping und muss natürlich irgendwie vom Betriebssystem aus änderbar sein - und unterliegt damit wie jede andere Hardware auch dem Zugriffsschutz(*).
Mhh der SRAM muss ja dann 1 MB groß sein oder? Ist das nicht etwas zu viel ?



Zitat
(*) Wenn du für Hardware einen getrennten Adressraum vorsiehst, ist das recht einfach. IN/OUT dürfen nur im Kernelmodus verwendet werden, denn MMU und Hardware sind Aufgaben des Betriebssystems. READ/WRITE dürfen immer verwendet werden und wenn auf eine ungültige Adresse zugegriffen wird, löst die MMU nachträglich einen Page Fault aus.
Naja hab eher an einen gemeinsamen Adressraum gedacht, wie wärs wenn ich den adressraum in 2 segmente unterteile(die größen der segmente sind immer gleich). Auf das erste Segment kann man nur im kernelmode zugreifen und auf das zweite kernelmode und usermode.




streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #239 am: 13. July 2013, 10:47 »
Zitat
Mhh der SRAM muss ja dann 1 MB groß sein oder? Ist das nicht etwas zu viel ?
Doch ist es, vor allem da es nicht 1MB sondern ganze 4MB sind (jede Adresse enthält 4 Byte um 32Bit Adressen aufnehmen zu können). Das Gute daran ist, das es wenn der SRAM einmal beschrieben ist es nie zu PageFaults kommen kann. Der riesengroße Nachteil ist dass es ewig dauert bis bei einem Taskwechsel der RAM neu beschrieben ist. Den SRAM verkleinern kann man leider auch nicht so ohne weiteres, da mann ja für jede virtuelle Adresse die von der CPU kommt einen Eintrag haben muss. Jetzt könnte man ja versuchen die Adressen auf weniger Einträge zu verteilen, womit wir dann wieder am Anfang wären.

Zitat
Naja hab eher an einen gemeinsamen Adressraum gedacht, wie wärs wenn ich den adressraum in 2 segmente unterteile(die größen der segmente sind immer gleich). Auf das erste Segment kann man nur im kernelmode zugreifen und auf das zweite kernelmode und usermode.
Das klingt wieder so kompliziert und gibt bei einem sehr kleinen Kernel sehr viel verschwendeten Platz. Ich würde eher dafür sorgen dass der Kernel bestimmen kann wann er in den Usermode wechselt, und das unabhängig davon wo er sich gerade befindet. Wichtig ist nur das der Usermode nicht einfach in den Kernelmode springen kann, das sollte dann nur über Interrupts geschehen, da der dann ausgeführte Code vom Kernel ist und nicht vom User.

 

Einloggen