Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Nachrichten - erik.vikinger

Seiten: [1] 2 3 ... 64
1
Offtopic / Re: Logisim CPU
« am: 20. January 2013, 21:25 »
:?
Entschuldige Bitte, aber Du weißt was ich meine.
2
Offtopic / Re: Logisim CPU
« am: 20. January 2013, 20:17 »
Hallo Tufelix,


dem was Svenska geschrieben hat kann ich nur zustimmen, aber ich hab noch ein paar weitere kleinere Problemchen gefunden (ja ich weiß das ihr alle meinen Perfektionismus ganz arg liebt):
  • Nr. 5 (der zweite SUBI) sollte wohl besser SUBRI heißen
  • Nr. 20 (RTI) würde ich erstmal weglassen, vor allem da es ja keine offensichtliche Methode gibt Interrupts aufzurufen, für die ersten Versuche spielen Interrupts/Exceptions usw. noch keine Rolle
  • Nr. 21..24 (die Shift-Befehle) da müsste die Mnemonik-Beschreibung anstatt "Rd,Rs1 or wert" eher "Rd,Rs1,Rs2 or wert" heißen (Rd und Rs1 sind immer vorhanden und Rs2 nur wenn keine Konstante benutzt wird)
  • Nr. 27,28 (MUL/DIV) diese beiden Befehle benötigst Du in jedem Fall jeweils für signed und unsigned, für schnelle Adressberechnung wäre auch eine simple Form der Multiplikation (nur Rs1 * Rs2 -> Rd, keine Unterscheidung zwischen signed und unsigned) nützlich
  • Nr. 29,30 (Load/Store) hier müsstest Du Bitte mal die Kodierung der einzelnen Adressierungsarten näher beschreiben (da reichen die hinteren 16 Bit des Befehls) und die Konstante könnte ruhig auch 12 Bit groß sein (ich denke das passt rein)

Mhh man kann auch doch nur bei ein paar bestimmten Befehlen prüfen ob die Operanden gültig sind(also bei Befehlen wo das wirklich nötig ist)
Ja, konzentriere Dich ruhig erst mal darauf das der Decoder die echt kritischen Dinge abfängt und den Rest kannst Du erst mal dem Assembler überlassen (also das dieser bestimmte Operanden-Kombinationen bei bestimmten Befehlen einfach nicht umsetzt, grundsätzlich sollte der Assembler keine Befehle umsetzen die die CPU bekanntermaßen nicht ausführen möchte oder die sonstwie problematisch sind). Mach Dir doch einfach dazu noch ein paar Gedanken und schreibe bei den Befehlen wo es Einschränkungen (von der CPU) geben soll diese mit dazu.

jetzt kann man auch alle register als adressregister benutzen.
Sehr gut, Du musst ja nicht gleich alles in Deiner CPU unterstützen was der OpCode theoretisch her gibt.


Man sieht auf jeden Fall das es vorwärts geht, weiter so! :-D
Und lass Dich nicht von so Miesepetern wie Kevin verunsichern, der Weg zu einer echten vollwertigen CPU ist nunmal nicht ganz so leicht wie bei einem OS das nur gut ausgetrampelten Pfaden folgt. (ich glaub jetzt mag er mich endgültig nicht mehr)


Grüße
Erik
3
Lowlevel-Coding / Re: Windowstreiber-Schnittstelle
« am: 20. January 2013, 19:16 »
Hallo,


Ich dachte, deine Architektur möchte die Speicherverwaltung etwas anders erledigen?
Ja, das ist der Plan. Trotzdem wird auch meine Speicherverwaltung gewisse Features anbieten (müssen) damit ein Treiber z.B. die physische Adresse zu einer virtuellen bekommt oder wenn in Linux gewisse Dinge mit einem kleinen Trick beschleunigt werden können dann kann ich das möglicherweise bei mir auch. Außerdem geht es mir nicht primär um meine eigene Plattform sondern allgemein um das Thema möglichst einfach vorhandene Treiber (egal aus welcher Quelle) in ein Hobby-OS zu bekommen.

Sicher kannst du die ganzen schmutzigen Details so implementieren, wie Linux das tut, aber dann kannst du theoretisch auch Linux benutzen.
Das möchte ich doch gar nicht, ich will doch nur eine User-Space-Library die vom Linux-Kernel gerade genug bietet damit ein Linux-Treiber funktioniert. Die Variante von „Linux on L4“ ist aus meiner Sicht höchstens ein erster Ansatz um überhaupt erst mal das Ziel erreichen zu können (und um erstmal alles das zu programmieren was diese Library für mein OS bieten muss) aber keine vernünftige Dauerlösung.

Die kritische Frage ist doch eher ob diese subtilen Dinge auch sauber dokumentiert sind.
Natürlich nicht, sonst wären sie ja nicht subtil
Wieso nur hab ich das geahnt?! Der Linux-Kernel ist doch das Vorzeigeprojekt der Open-Source-Scene aber eine anständige Doku ist für so ein riesen Ding wohl doch nicht mehr machbar. Schade, da der Linux-Kernel eigentlich die einzigste wirklich umfangreiche Quelle für Open-Source-Treiber ist.

Denk mal so: Du wirst auf deinem aktuellem PC kein Hobby-OS produktiv einsetzen. Wenn es überhaupt reale Hardware bekommt, dann ist das ältere Hardware.
Naja, nicht jeder hat einen älteren Zweitrechner parat nur um mal eben ein Hobby-OS aus dem iNetz auszuprobieren. Aber wenn Du an einen Produktiveinsatz denkst dann hast Du natürlich recht, wobei sich das eventuell mit Hobby-OS minimal beißt.

Einen beschleunigten 2D-Treiber gibt es ab Kernel 3.8, vgl. hier. Bei 3D sieht die Situation genauso aus wie bei allen anderen ARM-Herstellern.
Okay, bin überzeugt.

Die libusb kenne ich auch aber das es auf dieser Basis "richtige" Treiber gibt wusste ich noch nicht.
Da gibt es ganz viel Userspace-Kram, also Scanner und sowas. Mit HID, MSC und dem üblichen Zeug sieht das anders aus, weil das recht tief in den Subsystemen verwurzelt ist. Das gibt es schon, aber es bringt nichts, weil die Programme zwar die Hardware ansteuern, aber keine wirklichen Treiber sind.
Also eine ähnlich bescheidene Situation wie bei FUSE, zwar ein interessantes Konzept mit viel Potential aber es gibt einfach nicht genug reales Zeugs damit sich daraus auch wirklich was ernstzunehmendes ergibt. Schade!

ich meinte den umgekehrten Fall, paddr->vaddr. Linux hat die Speicherverwaltung so designt, dass da nur eine Konstante drauf addiert wird, was die Berechnung billig macht. Für IOMMUs gilt vermutlich das gleiche.
Also auch hier muss ich ehrlich sagen das es mir schwer fällt das zu glauben. Was ist mit reinen 32Bit-System auf denen der physische 4GB-Adressraum komplett ausgeschöpft ist? Ich kann mir nicht vorstellen das im Kernel-Space (der ja nur 2GB groß ist) auch nur alle MMIO-Ranges der HW-Geräte linear rein passen (den RAM lassen wir da mal außen vor). Und die IOMMU spielt in dieser Richtung keine Rolle, nebst dessen das wenn sie so simpel benutzt wird kann man sich das auch gleich ganz sparen.
Vor allem fällt mir gar kein Anwendungsfall ein wo ein Treiber eine physische Adresse in eine virtuelle Adressen umrechnen lassen müsste, so ein Feature möchte ich in meinem OS gar nicht erst anbieten.
In meiner Vorstellung arbeitet ein Treiber doch primär mit den Datenpuffern die er von den normalen Applikationen bekommt (mehr oder weniger direkt) und für diese bekommt der Treiber die virtuelle Adresse für welcher er dann die physische Adresse (welche optional per IOMMU wieder anders virtualisiert ist) benötigt.


Wozu sollte ich Code schreiben, den ich selber gar nicht brauche?
Ist natürlich eine berechtigte Frage. Trotzdem würde ich es als Vorteil erachten wenn das OS nicht einfach alle existierenden Treiber laden und starten muss und ich glaube auch nicht das eine kleine Tabelle (das Wort Datenbank war doch etwas übertrieben) mit den Class-Codes (für generische Treiber) oder Vendor/Device-IDs (für spezifische Treiber) so viel aufwendiger wäre.

Ich weiß, dass deine Herangehensweise eher ist, so lange zu designen, dass man nie etwas umgesetzt bekommt
das war nich lieb :cry:


Grüße
Erik
4
Offtopic / Re: Logisim CPU
« am: 19. January 2013, 11:54 »
Hallo,


Dachte an Shift-Befehle so wie wikinger beschrieben hatte...
Okay, ich denke das Svenska auch an diesen Shifter-Operanden von ARM dachte den die speziellen PPC-Befehle haben 5 Operanden und sowas gibt es wimre beim klassischen ARM32 nicht (diese 5 Operanden würden bei ARM32 zusammen 23 Bit belegen).

Wofür braucht man eigentlich die Sprungbefehle JA,JAE,JB,JBE. Kann man da nicht für JA auch ein JE Befehl nehmen und für JB ein JL?
JA (>) und JE (==) sind zwei unterschiedliche Dinge und deswegen wirst Du auch beide brauchen. JL und JB sind auch unterschiedlich da ersteres für signed und letzteres für unsigned ist. Bitte beschäftige Dich mal mit der Zahlendarstellung im Zweierkomplement für signed und unsigned.
Das Zitat mit den Shift-Befehlen passt zu Deiner Frage nicht.

Mhh wenn ich jetzt schon 2 Quellregister hab könnte ich eigentlich ja auch 2 Zielregister einbauen
Solange Du nur bei Registern bleibst sollten in Deine 32Bit-Befehle locker 4 Operanden rein passen aber es gibt nur wenige Befehle die so viele Operanden wirklich benötigen und in Deiner Pipeline (also in der internen dekodierten Befehlsdarstellung) musst Du trotzdem immer 4 Operanden vorsehen (auch bei Befehlen die das nicht nutzen). Damit wäre ein R1 * R2 := R3:R4 möglich (R3 ist der High-Part des Produkts und R4 der Low-Part).
Bei der Division wird es aber noch schwieriger, eine vollwertige Division ist eigentlich ein 5 Operanden-Befehl: R1:R2 / R3 = R4,R5 (R1 ist der High-Part des Dividend und R2 der zugehörige Low-Part, R3 der Divisor, R4 der Quotient und R5 der Rest). Bei Deinen 32Bit-Befehlen sollten auch 5 Register problemlos kodierbar sein aber das macht Deine interne Darstellung sehr umfangreich. Hier kommst Du eben in das Problem das Du dafür eine fette interne Befehlsdarstellung brauchst die aber nur von sehr wenigen Befehlen wirklich ausgereizt wird.

was passiert eigentlich wenn man bei den 2. Zielregister das selbe Register angibt wie beim ersten Zielregister?
Das musst Du als CPU-Designer festlegen. Deswegen wolltest Du doch diesen Job, oder? ;)
Auf meiner CPU ist das verboten, der Decoder wird solche Befehle als Undefined-OpCode verwerfen und es kommt eine Exception. Aber es macht auch den Decoder komplexer wenn er für jeden Befehl individuell prüfen muss ob die aktuelle Kombination aus Operanden gültig ist, hier ist es wichtig ein gutes Mittelmaß zu treffen damit der Decoder mindestens den kritischen Unfug abfängt aber auch nicht zu komplex wird. Dieses Problem existiert auch bei den Speicher-Lesebefehlen wenn das Zielregister mit dem Adressregister übereinstimmt, theoretisch sollte das funktionieren aber wenn Du das Adressregister Inkrementierst/Dekrementierst darf es nicht noch zusätzlich mit den gelesenen Daten überschrieben werden.


Grüße
Erik
5
Lowlevel-Coding / Re: Windowstreiber-Schnittstelle
« am: 18. January 2013, 21:02 »
Hallo,


(z.B. dass vaddr->paddr niemals einen page table walk durchführt und daher schnell ist)
Also wenn damit gemeint ist das eine virtuelle Adresse in die zugehörige physische Adresse umgewandelt wird glaube ich nicht mal das gar kein Page-Teble-Walk durchgeführt wird, in irgendeiner Art von Datenstruktur (was natürlich nicht zwangsläufig eine Page-Table für die CPU sein muss) muss diese Information schließlich verwaltet werden. Spätestens wenn eine I/O-MMU ins Spiel kommt ist diese Funktion nicht mehr trivial. Auch müsste überlegt werden ob diese Performance noch erreicht wird wenn die virtuelle Adresse zu einem der User-Spaces gehört.


Zu sagen, CDI habe deshalb diese Zielgruppe, ist aber falsch. CDI hat keine Zielgruppe.
Sorry, da habe ich mich offensichtlich falsch ausgedrückt. Mir ist schon klar dass das keine absichtliche Entscheidung der Entwickler war primär die HW der Virtualisierer zu unterstützen sondern das es einfach ein logischer Schritt war da die Entwickler wohl oft (aber sicher nicht ausschließlich) mit einer virtuellen Maschine arbeiten. Es ging mir eher darum dass das momentan real vorhandene Treiber-Arsenal von CDI einen gefühlten Schwerpunkt auf diese Art der Geräte hat.

Aus meiner Sicht ist z.B. der Aspekt das die Treiber wohl selber bestimmen müssen ob sie sich für ein bestimmtes Gerät zuständig fühlen ein konzeptioneller Nachteil, IMHO wäre es besser wenn z.B. ein zentraler PCI-Service alle Geräte nimmt und in einer Datenbank (o.ä.) nachschaut welchen Treiber er für jedes Gerät laden soll. Ein anderer Nachteil ist z.B. das pro Gerät nur ein IRQ möglich ist.


Grüße
Erik
6
wenn mit dem Segmentwechsel also nicht der Rang gewechselt wird wie dann?
Der aktuelle Ring wird immer mit dem Wechsel von CS geändert aber da gibt es eine Menge Regeln zu beachten (die von der CPU durchgesetzt werden) damit nicht jeder (Schad)-Code hier alles tun darf. Der Wechsel von CS kann automatisch passieren z.B. bei einem Interrupt/Exception oder einem HW-Kontext-Wechsel oder auch manuell angetriggert werden wie mit einem FAR-CALL.
7
Hallo,


im Beispielkernel wird mit diesem Code in den Ring3 gewechselt
Ich glaube das ist schon Dein erstes Verständnisproblem. Wenn ich den Kommentar in dem Code richtig deute dann ist dieser Code Bestandteil des Kernels und wird im Ring 0 ausgeführt und sorgt nur dafür das in den Segmentregistern DS und ES auch passende Selectoren drin sind damit der Kernel-Code (der ja DS und ES implizit benutzt) richtig funktioniert.

wieso wird beim Segmentregister ax kein Invalid Opcode ausgelöst.
AX ist kein Segmentregister. siehe http://www.lowlevel.eu/wiki/X86#Segmentregister

Hat dass was mit dem InterruptFlag zu tun dass im Interrupt Context die CPU automitisch die Segmentregister sichtbar macht?
Die Segmentregister sind in jedem Ring sichtbar (also lesbar) und auch änderbar (also beschreibbar), eine Exception kommt nur dann wenn auf Speicher zugegriffen werden soll und der im Hintergrund geladene Descriptor (der über den Selector selektiert wird) ungültig ist oder nicht die passenden Zugriffsrechte anbietet. Mit dem Interrupt-Flag hat das nichts zu tun.


Grüße
Erik
8
Lowlevel-Coding / Re: Windowstreiber-Schnittstelle
« am: 18. January 2013, 20:22 »
Hallo,


Da gibt es irgendeine Art Bibliothek für L4 (wimre), die den Linuxkernel darstellt, und wenn man Treiber gegen die linkt, kann man die halt im Userspace ausführen und Linuxtreiber unter L4 benutzen.
Hm, das ist doch schon mal ein interessanter Schritt in die richtige Richtung, auch wenn es ein paravirtualisiertes Linux ist, also auf eine Art von User-Mode-Linux hinausläuft was ich ja eigentlich nicht möchte. Um z.B. einen Ethernet-Treiber zu bekommen möchte ich mir eigentlich nicht z.B. den IP-Stack des Linux-Kernel als Ballast in meinen User-Mode-Prozess holen, ich denke schon das es besser wäre gezielt die Funktionen die mein OS selber bieten will aus dem Linux-Kernel auszublenden und dann nur das raus zu filetieren was als Abhängigkeiten übrig bleibt. Zu dem was mein OS (bzw. meine User-Mode-libc) selber bieten gehört IMHO auch die Speicherverwaltung, nur Dinge wie eben das mappen von physischen Speicherressourcen der betreffenden Hardware muss ich passend abfangen und mit einem Syscall an mein OS behandeln. Mir ist klar das diese Vorgehensweise trotzdem einiges an Arbeit erfordert und auch mein Mapping-Code je nach Geräte-Type unterschiedliche Dinge bieten muss, trotzdem halte ich das für einen vernünftigen Ansatz um nahezu beliebige Treiber von Linux in mein OS zu holen.


Außerdem verlassen sich Treiber u.U. auf bestimmte Eigenheiten der Speicherverwaltung (z.B. dass vaddr->paddr niemals einen page table walk durchführt und daher schnell ist), die bei dir nicht gegeben sind.
Um Linux-Treiber automatisiert übernehmen zu können, musst du in deiner Semantik so nah am Original sein, dass du dir die Kopie auch gleich sparen kannst.
Also davon bin ich jetzt noch nicht überzeugt. Letztendlich kocht Linux auch nur mit Wasser, also warum sollte ich diese Features/Eigenheiten nicht auch hinbekommen?
Die kritische Frage ist doch eher ob diese subtilen Dinge auch sauber dokumentiert sind.

Ich behaupte, dass die durchschnittlichen Nutzer von Aldi/Saturn/Mediamarkt/...-PCs nicht die Zielgruppe für Hobby-OSe sind.
Okay, Punkt für Dich. ;)

Außerdem fängt das Problem schon mit NVidia-Chipsätzen an. :-)
Schon klar, aber wäre es nicht cool wenn tyndur trotz NVidia-Chipsatz eine vernünftige Graphik bieten könnte? Mal davon abgesehen das tyndur überhaupt Graphik richtig unterstützen müsste (ja ich weiß das es da erste Ansätze gibt).

Nicht alle interessanten Treiber existieren für x64
Aber beim heutigen Verbreitungsgrad von x64 sind die Lücken bereits recht dünn. Welcher HW-Hersteller kann es sich den leisten das seine HW von aktuellem Windows nicht unterstützt wird?

und bei ARM wäre ich auch sehr überrascht, wenn sich dort ein halbwegs gebrauchbares Arsenal finden würde
Okay, aber immerhin soll z.B. der Tegra 3 unterstützt werden und für diesen z.B. einen halbwegs brauchbaren Grafik-Treiber zu bekommen ist doch schon mal was.


Das Thema USB ist auch noch so ein Punkt, ja ich hatte bisher primär an PCI-Hardware gedacht.
Die libusb kenne ich auch aber das es auf dieser Basis "richtige" Treiber gibt wusste ich noch nicht. Wenn man auf diesem Weg zumindest HID und Mass-Storage bekommt wäre das doch schon mal ein echt großer Schritt, auch wenn einem immer noch die Hubs und der Host-Controller als Hausaufgabe bleiben.


Das heißt, du willst den kompletten Subsystemcode mit rauskopieren? Du kannst es ja mal versuchen, ob du auf diese Weise irgendwohin kommst, aber an irgendeiner Stelle musst du einen Strich ziehen. Die komplette Speicherverwaltung willst du ja vermutlich nicht kopieren. ;)
Ich denke das gerade vom betreffenden Subsystem eh nicht so viel Code kommt, wenn wir mal beim Beispiel des Ethernet-Treibers bleiben dann will ich doch gerade den IP-Stack usw. selber anbieten. Aus meiner Sicht sind eher die Funktionen kritisch die wirklich irgendwo im Kernel liegen und nicht so offensichtlich zu Ethernet-Treibern gehören. Die Speicherverwaltung aus dem Linux-Kernel zu kopieren geht natürlich gar nicht, IMHO noch nicht mal bei einem paravirtualisiertem Linux-Kernel und weil man gerade die eh für alle Treiber benötigt sollte es auch nicht so arg schwer fallen hier einmal was anständiges zu Entwickeln. Außerdem hoffe ich das sich die API zur Speicherverwaltung nur selten ändert (schon weil es da extrem viele Aufrufe gibt die man ändern müsste, da vertraue ich einfach auf die natürliche Faulheit des Menschen).


Grüße
Erik
9
Offtopic / Re: Logisim CPU
« am: 18. January 2013, 19:33 »
Hallo,


Ich glaube, wir reden aneinander vorbei, Erik.
Ja, das glaube ich jetzt auch. Fragt sich nur was Tufelix dachte.

Ich rede von Instruktionen wie rlwimi oder rlwinm auf PPC.
Ja, diese beiden Befehle sind cool. rlwimi hab ich auf meiner CPU auch aber etwas anders, es geht dabei ja im Prinzip darum aus einem Register von einem beliebigen Bitoffset eine bestimmte Anzahl an Bits (zusammenhängend aber ggf. mit Umlauf) aus einem Register raus zu holen und in ein anderes Register an einem anderen beliebigen Bitoffset rein zu packen (auch wieder zusammenhängend mit optionalem Umlauf) und die übrigen Bits des Zielregisters unverändert zu lassen. lrwinm hab ich aber nicht als Einzelbefehl da sich sowas auch einfach mit einer Rotation und einem anschliessendem AND darstellen lässt (wobei ich das dank des Shifter-Operanden, den ich doch vorgesehen habe, auch als Einzelbefehl haben kann aber dafür die Maske bereits in einem anderen Register vorhanden sein muss) und ich auch nicht so ganz sicher bin ob man sowas oft braucht.


Grüße
Erik
10
Lowlevel-Coding / Re: Windowstreiber-Schnittstelle
« am: 18. January 2013, 15:58 »
Hallo,


der große Vorteil eines Monolithen ist, dass du interne Funktionen ohne Overhead aufrufen kannst, es also bestimmte Funktionalität nur einmal im gesamten Kernel geben muss. Da sind Bugfixes maximal effektiv.
Also wenn diese Funktionen in einer DLL liegen dann sind sie aus mehreren User-Mode-Treibern mit genau so wenig Overhead aufzurufen und belegen auch nur einmal RAM/Cache und lassen sich genau so zentral warten. Sorry, aber das zählt nich. Der große Nachteil dieses Funktions-Sharings ist das wenn ein Subsystem-Entwickler sich so eine Funktion ausgedacht hat und diese dann plötzlich von den Treibern anderer Subsysteme auch benutzt wird das dann plötzlich (möglicherweise sogar ohne es zu wissen) der erste Entwickler seine Funktion nicht mehr einfach so modifizieren kann da das plötzlich unvorhergesehene Rückwirkungen auf ganze andere Dinge im Kernel hat. Diese Art von Spagetti-Code ist grundsätzlich nicht schön und ich persönlich würde gerne 0,2% System-Performance opfern wenn dafür ein stabileres System entsteht.

Viele API-Änderungen sind aber nur relativ klein bzw. lassen sich in den Treibern ohne größeren Aufwand automatisiert umsetzen
Ich hätte jetzt eher daran gedacht das ich aus einer bestimmten Kernel-Version bestimmte Treiber heraus filetiere, indem man ein Tool benutzt dem man sagt welche Dateien man unverändert bekommen will (den Treiber) und dieses Toll dann die Abhängigkeiten im restlichen Kernel iterativ durchgeht und genau das was benötigt wird mit ausschneidet. Letzteres abzüglich der Funktionen die ich selber anbieten muss und auch nur bei diesen Funktionen muss ich zuerst (händisch) prüfen ob sich dort die API und/oder die Funktionalität geändert hat.

Schlimmer ist, dass die ABI nicht stabil ist, was Binärtreiber verunmöglicht. ;)
Einige HW-Hersteller haben mehr oder minder erfolgreich vorgeführt das auch dieses Problem lösbar ist. ;)

Theoretisch kannst du jeden Treiber mit einem halben Linux verheiraten und im Userspace laufen lassen, ob das aber mehr Spaß macht als den Treiber zu reversen und neu zu entwickeln, kann ich nicht einschätzen.
Es geht mir nicht um den Spaß sondern darum ein Ziel mit möglichst geringem Aufwand zu erreichen und ich will auch nicht den halben Linux-Kernel sondern nur genau das was der Treiber benötigt und nicht eh von mir kommen muss (weil gewisse Dinge eben zu meinem OS passen müssen, alles andere würde auf nahezu vollwertiges User-Mode-Linux hinauslaufen).

Vermutlich kommst du da mit den BSD-Treibern eher weiter, die haben da - soweit ich das einschätzen kann - kleinere Schnittstellen. Andererseits ist z.B. der nouveau-Treiber von den Entwicklern als Kernel- und Userspace-Treiber ausgelegt worden, damit die bei der Entwicklung "mal eben schnell" eine Änderung testen können.
Okay, es gibt also mehr Quellen als nur den Linux-Kernel, wenn mein oben beschriebenes Tool flexibel genug ist sollte auch das kein Problem sein.

Ich denke, wenn man sich auf Treiber einer Klasse (z.B. Ethernet) beschränkt, kann man Linux-Treiber portieren. Wenn man aber alle/viele verschiedene Treiber übernehmen will, läuft das auf eine Reimplementation von Linux im eigenen Kernel raus.
Naja, also wenn dann geht es IMHO schon darum die typischen PCs die Media-Markt/Saturn/ALDI/... in den letzten X Jahren verkauft haben zu unterstützen damit mein kleines Hobby-OS auf möglichst vielen potentiellen PCs läuft. Wenn wir uns mal ansehen für welche HW es CDI-Treiber gibt dann muss man ganz klar sagen das deren Zielgruppe die virtuellen PCs von VMware und Co sind. Klar auch das ist ein Markt, wenn man damit (und den anderen Nachteilen von CDI) zufrieden ist dann ist CDI eine interessante Wahl aber wenn man mehr will dann ist es eventuell ratsam doch mal die Alternativen zu prüfen.

Windows-Treiber haben den Vorteil der Verfügbarkeit, sind aber meist hinreichend schlecht/instabil programmiert.
Um ersteres geht es mir doch und ob ich als Hobby-OS-Dever im zweiten Punkt mit eigenen Treibern so viel besser abschneiden würde steht auf einem anderen Blatt (deswegen bin ich ja so an den Linux-Treibern interessiert, die sind ebenfalls gut verfügbar und meistens von mindestens ebenwürdiger Qualität).

Außerdem ist es trotzdem eine ziemlich heftige API, die man unterstützen muss (Binärformate, ...).
Das ist wohl war. Die Windows-Treiber-API gibt es in verschiedenen Geschmacksrichtungen und jede Treiber-Sorte benötigt eine eigene API und dann hat man oft sogar noch die Wahl ob der Treiber im User-Mode oder im Kernel-Mode laufen soll. Aber gemessen an dem Aufwand den man investieren müsste um alle gewünschten Treiber selber zu entwickeln ist das vielleicht gar nicht mal so viel wie es scheint. Nebst dessen das man sich vielleicht bei ReactOS bedienen kann.

Portabel ist es dann auch nicht, aber bei einem Hobby-OS tut das nicht unbedingt weh.
Zumindest x86 in 32Bit und 64Bit und demnächst auch ARM in 32Bit und 64Bit sind doch schon mal was. Was will den der klassische Hobby-OS-Dever (der keine eigene Plattform bauen möchte, so wie wir beide) mehr?


Grüße
Erik
11
Offtopic / Re: Logisim FPGA
« am: 18. January 2013, 14:42 »
Hallo,


eine FPGA virtuell nachzubauen ist IMHO schon ein ziemlich umfangreiches Unterfangen. Das schwierige dabei sind aber nicht die einzelnen Logik-Zellen sondern eben das Routing dazwischen (das belegt wimre auch in dem Bitstreams für die FPGAs den meisten Platz). In einem simulierten FPGA (ohne Signallaufzeiten) könnte man vielleicht der Einfachheit halber an jeden Eingang einer Logik-Zelle einen großen MUX anschließen der sich aus allen Ausgängen aller Logik-Zellen bedienen kann, aber in realen FPGAs geht das natürlich nicht. Da werden die Signale durch komplexe Routing-Netze durchgeschaltet (so ähnlich wie das alte analoge Telefonnetz nur viel stärker vernetzt und verwoben).


Grüße
Erik
12
Offtopic / Re: Logisim CPU
« am: 18. January 2013, 14:33 »
Hallo,


Wobei ich keine Ahnung habe, wie doof sowas umzusetzen ist.
Ziemlich doof, glaub mir.
Außerdem ist ARM32 meines Wissens nach die einzigste real existierende CPU die sowas überhaupt hat (auch in ARM64 ist das wohl nicht mehr drin), was sicher auch etwas über die Nützlichkeit dieses Features aussagt.


mein CPU wird erstmal ohne Pipeline arbeiten, da wird es sicherlich keine Probleme wegen der abhängigkeit geben...
Ja, bei mit ohne Pipeline sollte das keine Probleme mit der Performance o.ä. machen.

Werde dann wohl auch die 3-Operanten Befehle einbauen...
Das alleine bringt schon einiges an Performance weil weniger Befehle für die selbe Sache benötigt werden.

Barrel-shifter könnte ich eigentlich auch einbauen
Ich denke das solltest Du fürs erste lassen, damit wird Deine CPU um einiges komplexer und vor allem wird die Codierung der Befehle deutlich komplexer. Versuch doch erst mal eine möglichst einfache CPU zuverlässig ans laufen zu bekommen bevor Du Dir die nächste Schwierigkeitsstufe vornimmst. ARM hat diese Shifter-Operanden auch nur bei manchen Befehlen und für Konstanten, letzteres Problem hast Du nicht weil Du in Deine 32Bit Befehle eine 16Bit-Konstante immer ohne Verrenkungen komplett rein bekommst.

dann werd ich auf die ersten 4 bits der Konstanten-bits die distanz-bits legen.
Hä, wie meinen?

Nun kann man eigentlich etwas an den Load und Store-Bits verbessern?
Versuch doch erst mal Dein Konzept als ganzes mit den jüngsten Vorschlägen dieses Thread neu aufzubauen und dann sehen wir wie weiter verbessert werden kann.

Zu MUL/DIV möchte ich aber dennoch was schreiben: Du solltest Dir überlegen ob Du das Produkt der Multiplikation in voller Bitgröße haben willst was eben immer 2 Ziel-Register erfordert, solange Du nur die untere Hälfte des Produkts hast brauchst Du auch nicht zwischen signed und unsigned unterscheiden aber wenn Du mehr willst musst Du das beachten. Auch für die Division könnte es sich lohnen wenn Du zwei Ziel-Register ansprechen kannst da es ja dort noch den Rest gibt (wird u.a. für den %-Operator von C benötigt). Bei der Division muss wimre immer zwischen signed und unsigned unterschieden werden. Ein Speicher-Lesebefehl mit Pre/Post-Inkrement/Dekrement hat auch immer 2 Ziel-Register (das wo die gelesenen Daten rein gelegt werden und das Adressregister das modifiziert wird).


Grüße
Erik
13
Lowlevel-Coding / Re: Windowstreiber-Schnittstelle
« am: 18. January 2013, 13:47 »
Hallo,


... Selbstverständlich machen sie auch ausgiebig Gebrauch davon, ...
War nicht gerade das der Haupt-Kritik-Punkt den die Pioniere der Micro-Kernel an den damaligen OSen hatten? Und in den mindestens 30 Jahren haben die OS-Dever die Monolithen schreiben nichts gelernt? Es ist ja nicht so das mich das überraschen tät (so sind Menschen eben) aber entsetzt bin ich da jetzt doch.

Das andere Problem ist, dass die Schnittstellen innerhalb von Kernel nicht stabil sind
Das ist aus meiner persönlichen Sicht der größte Kritikpunkt am Linux-Kernel überhaupt (mal davon abgesehen das er ein Monolith ist ;) ) und ich wette viele Firmen die Hardware herstellen sehen das ähnlich.

Mal vom Aufwand abgesehen, da es sich beim Linux-Kernel ja um GPL-Code handelt sollte es doch für ein Micro-Kernel-OS möglich (und auch legal) sein alles was man für einen bestimmten Treiber benötigt aus dem Linux-Kernel komplett hinaus zu filetieren und als eigenständigen User-Mode-Prozess laufen zu lassen oder? Man müsste doch eigentlich nur die Teile des Linux-Codes anpassen/ersetzen die das Treiber-Management (z.B. IRQ-Handler an/ab-melden oder HW-Speicher ein/aus-blenden) betreffen oder?


Zumindest steckt in diesem Thread ein wesentliches Kernproblem von "Hobby"-OSen: wie unterstütze ich mit möglichst vertretbaren Aufwand möglichst viel Hardware?
Im Endeffekt gibt es genau 2 Möglichkeiten dieses Problem anzugehen: entweder man übernimmt die Treiber eines anderen Systems oder man programmiert eigene Treiber.
Das die zweite Variante ein extrem hoher Aufwand ist (den man ja gerade nicht will) ist ziemlich offensichtlich aber das die erste Variante ein eventuell noch größerer Aufwand darstellt ergibt sich erst auf den zweiten Blick.
Nach allem was ich in den letzten Jahren zu diesem Thema an Informationen gefunden hab muss ich ganz ehrlich sagen das wenn man Variante 1 wählen möchte das dann die Windows-Treiber-API durchaus recht interessant erscheint (solange man auf einer Plattform arbeitet die von Windows ebenfalls nativ unterstützt wird könnte man sogar Closed-Source-Treiber übernehmen) da diese recht stabil und auch einigermaßen gut Dokumentiert ist, außerdem ist die Windows-Treiber-API auf Flexibilität und Performance ausgelegt was man von allen alternativen APIs (CDI/UDI/...) wahrlich nicht behaupten kann.

Ich würde mir wünschen das diese Kernfrage hier vielleicht noch ein wenig Diskutiert wird.


Grüße
Erik
14
Offtopic / Re: Logisim CPU
« am: 15. January 2013, 15:38 »
Hallo Tufelix,


Wo das NOP liegt ist mMn eher egal aber ich möchte Kevin zustimmen und würde dafür sorgen das wenn der Befehl komplett aus 0-Bits besteht das dann eine Undefined-OpCode-Exception kommt. Das selbe auch wenn der Befehl komplett aus 1-Bits besteht da viele FLASHs und EEPROMs im unprogrammierten Zustand immer 0xFF liefern. Aber in der Realität wird das nur bei sehr wenigen CPUs so gehandhabt und die funktionieren auch alle also ist es wahrscheinlich relativ egal. Auf NOP ganz verzichten würde ich aber trotzdem nicht, ein NOP zeichnet sich meiner Meinung nach dadurch aus das dieser von keinem anderen Befehl abhängig ist und auch kein anderer Befehl vom NOP abhängt, bei einem MOV R0,R0 ist das nicht so einfach gegeben da es auch andere Befehle geben kann die R0 benutzen. Eine Option wäre natürlich diesen MOV R0,R0 im Decoder als Sonderfall zu behandeln der dann innerhalb der eigentlichen Pipeline als echter NOP dargestellt wird (und auch der Disassembler zeigt für die Bitkombination die MOV R0,R0 entspricht immer NOP an) aber dieser NOP eben keinen eigenen OpCode hat.


Da Du ja 32 Bit pro Befehl hast würde ich den Aufbau minimal ändern:
6 Bit  | 5 Bit | 5 Bit |  16 Bit
OpCode |  RD   | RS(1) | Konstante oder RS2

64 maximal mögliche Befehle dürften für Dein Konzept komplett ausreichen (Du hast wirklich einige Redundanz drin) und 32 anstatt 16 Register sind auf jeden Fall nicht zu verachten. Ein drittes Register (aus dem aber nur gelesen werden kann) ist ebenfalls eine gute Idee da damit zerstörungsfreie 3-Operanden-Befehle möglich werden (alle anständigen RISC-CPUs die was auf sich halten können sowas und die Compiler lieben das abgöttisch).


Bei den bedingten Sprüngen reichen 6 Varianten völlig aus. Im Assembler Mnemonik solltest Du folgende 18 Varianten haben: JE, JNE, JA, JAE, JB, JBE, JNA, JNAE, JNB, JNBE, JG, JGE, JL, JLE, JNG, JNGE, JNL, JNLE (die ersten 2 sind für signed und unsigned, die nächsten 8 für unsigned und die letzten 8 für signed). Damit sind alle Vergleichsmöglichkeiten zwischen 2 Integer-Werten abgedeckt. Die beiden ersten Varianten JE und JNE müssen so auch als OpCode verfügbar sein, die anderen 16 Mnemoniks lassen sich mit 4 OpCodes darstellen : JA ist das selbe wie JNBE und JAE ist das selbe wie JNB usw. und schon sind es nur noch diese 8 Möglichkeiten : JA, JAE, JB, JBE, JG, JGE, JL, JLE (ich hab mal alle die Varianten mit N gestrichen). Zur weiteren Halbierung muss Dein Assembler in der Lage sein die Register zu vertauschen : JB R1,R2,Destination ist das selbe wie JA R2,R1,Destination usw. und schon sind es nur noch 4 richtige Vergleiche (2 für unsigned und 2 für signed), zusätzlich zu JE und JNE.
Der Aufbau für Deine bedingten Sprünge wäre also:
OpCode (6 aus 64) | RA (5Bit) | RB (5Bit) | Destination (16Bit)
wobei RA und RB immer nur gelesen werden (diese Befehle also nie irgendwelche Register ändern), ob Destination absolut oder relativ ist bleibt erst mal Dir überlassen aber ich würde für eine einfache CPU bei der es keine Möglichkeit gibt Code von einem externen Datenträger zu Laden bei absolut bleiben, spätestens der Linker weiß ja an welche Adresse er jeden Befehl packt und kann deswegen immer absolute Sprünge bauen (und der Decoder in der CPU wird einfacher wenn er nicht das absolute Sprungziel erst berechnen muss).

Bei Deinen mathematischen Befehlen (da schließe ich AND/OR/XOR mit ein) würde ich einen vergleichbaren Aufbau nutzen:
OpCode (12 aus 64) | RD (5Bit) | RS1 (5Bit) | Konstante (16Bit) oder RS2 (5Bit)
Die OpCodes sind mMn : ADD, ADDI, SUB, SUBI, SUBR, SUBRI, AND, ANDI, OR, ORI, XOR, XORI (wobei SUBR durch SUB mit vertauschten RS1 und RS2 ersetzt werden kann aber ich lass den mal der Konsistens wegen drin).
Befehle mit I am Ende funktionieren so : RD <= RS1 [Operator] Konstante
Befehle ohne I am Ende entsprechend : RD <= RS1 [Operator] RS2
Bei allen diesen Befehlen ist es egal in welcher Reihenfolge die beiden Quell-Operanden stehen nur bei SUB nicht und deswegen gibt es den SUBRI damit eben auch RD <= Konstante - RS1 möglich ist (ARM hat sowas auch aber dort vor allem deswegen weil nur einer der beiden Operanden ein Shifter-Operand sein kann und diese Fähigkeit eben nicht nur dem Subtrahend sondern auch dem Minuend zur Verfügung stehen soll).

INC und DEC wird als eigenständiger OpCode nicht benötigt da sich das mit ADD und SUB darstellen lässt. NEG ist gut aber läst sich mit SUBRI RD,RS1,0 darstellen, dafür hast Du NOT (alle Bits invertieren) vergessen aber der lässt sich mit XOR RD,RS1,0xFFFF darstellen.

MOV und LDK sollten auf jeden Fall beide so bleiben und hätten diesen Aufbau :
MOV | RD (5Bit) | RS (5Bit) | ungenutzt
LDK | RD (5Bit) | ungenutzt | Konstante (16Bit)
Wenn bei MOV RD und RS identisch sind lassen sich damit Spezial-Fälle umsetzen: z.B. wenn RD == RS == 0 zutrifft könnte damit ein NOP gemeint sein. Mit den Werten 1..31 in RD/RS lassen sich noch andere Spezial-Fälle abdecken. Solche Spezial-Fälle in einen vorhanden Befehl mit hinein zu kodieren spart Dir zwar OpCodes aber macht dafür den Decoder komplizierter, in der Pipeline hat das aber keine Konsequenzen da die Spezial-Fälle dort eh als eigenständige Befehle benötigt werden.

Zu Shiften und Rotieren reichen 4 Befehle da ROR sich durch ROL abbilden lässt und diese müssten folgenden Aufbau haben:
OpCode (4 aus 64) | RD (5Bit) | RS (5Bit) | ein Bit das unterschiedet ob der Anzahl der Shifts bzw. Rotationen als Konstante oder aus einem Register kommt | unbenutzt (10 Bit) | Konstante (4Bit) oder RS2 (5Bit)
woraus dann diese Mnemoniks entstehen : SHR, SHRI, SHL, SHLI, SAR, SARI, ROL, ROLI was in C so aussieht RD = RS [Operator] Konstante oder Variable (in RS2).

Bis jetzt sind es gerade mal 24 Befehle und wir haben schon fast alles was wichtig ist, es fehlen nur noch Multiplikation/Division, unbedingte Sprünge bzw. Funktionsaufrufe und die Speicherzugriffe.
Aber dazu schreibe ich später noch was wenn Du das wirklich möchtest (meine Beiträge ziehen sonst wieder so arge Kritik wegen ihrer übergebührlichen Länge auf sich ;) ).


Grüße
Erik
15
Lowlevel-Coding / Re: Dynamische Prozessortaktung
« am: 12. January 2013, 20:29 »
Hallo,


und soviel Ich weiß geht das übers SMBios.
Dafür gibt es auf der x86-Platform nahezu unzählig viele Wege, je nach Baujahr des PC kann das auch das SMBios sein. Heute ist ACPI aktuell.

aber wie weiß das SMBios ob gerade ein aufgebrezeltes 3D-Spiel oder nur HintergrundProzesse laufen?
Für die Priorität der ausgeführten Prozesse interessiert sich das SMBios gar nicht, wichtig ist nur ob überhaupt irgendein Prozess sinnvolle Arbeit mit der CPU durchführt oder ob die CPU schlafen geschickt wird.

Hat das was mit der NOP Instruktion zu tun?
Nein, wenn dann eher mit HLT. Wann immer die CPU einen HLT-Befehl ausführt wechselt diese in einen (einstellbaren) Schlafmodus. Dank heutigem Multicore und Hyperthreading ist das aber insgesamt eine recht komplexe Angelegenheit geworden, in der ACPI-Spec finden sich zu diesem Thema sicher ein paar hundert Seiten dehnen Du bestimmt nähere Einzelheiten entnehmen kannst (falls Du dieses typisch verkorkste Spezifikations-Englisch entschlüsseln kannst).

Mittlerweile gibt es so viele allgemeine Fragen über X86 oder Prozessoren allgemein(zB wie man sie baut^^),dass es sinnvoll wäre ein eigenes Board zu öffnen, damit nicht alles in Offtopic verschwindet.
Also für ein eigenes Board das sich primär um reine Hardwarethemen dreht sehe ich nicht genug Bedarf und da Offtopic auch ansonsten nicht gerade überrannt wird denke ich das diese Themen hier recht gut aufgehoben sind.


Grüße
Erik
16
Offtopic / Re: Logisim CPU
« am: 12. January 2013, 13:06 »
Hallo,


... dann fallen da sämtliche Heimcomputer und alle CPUs raus, die man üblicherweise als 8-Bit-CPUs bezeichnet ...
Ja, aber das liegt daran das man zur Klassifizierung üblicherweise die Datenpfadbreite in der ALU heranzieht. Ich persönlich bin aber der Meinung dass das nicht so ganz korrekt ist, zumindest die vom CPU-Kern nativ unterstützte Adressbreite sollte ebenfalls etwas berücksichtigt werden. Stell Dir mal vor es würde jemand eine CPU bauen die zwar nur über 8Bit breite Register und eine entsprechende ALU verfügt aber dafür in der Lage ist immer 4 dieser Register zu einem Pointer zusammenzufassen um damit 4GB Speicher flach zu adressieren und dazu vielleicht sogar noch vollwertiges Paging beherrscht (so das sogar ein normales unbeschränktes Linux drauf laufen könnte), würdest Du das immernoch als 8Bit-CPU bezeichnen?

Von der Adressgröße beim Programmcode wollen wir erst gar nicht reden, es gibt z.B. AVRs die mehr als 64k-Befehle adressieren können (wobei jeder Befehl auch 16Bit groß ist) und die trotzdem noch offiziell als 8Bit-CPU klassifiziert werden.

Aber letztendlich ist das eine rein akademische Diskussion da in der Realität zur Zeit sogar die aller kleinsten CPUs (in Taschenrechnern und Waschmaschinen) langsam gegen 32Bitter ausgetauscht werden. Kleine Cortex-M0-µC sind teilweise bereits für unter 1 Dollar (bei großen Stückzahlen) zu bekommen und auch für die Entwickler ist es einfacher keinen exotischen Compiler zu benötigen der in der Lage ist mit dem zusammengestückelten Adressraum der 8Bit-Generation umzugehen.

... dass ein OS unter diesen Bedingungen ziemlich unmöglich ist.
Vor allem auch ziemlich nutzlos. Mehr als eine einfache Library (die ins eigentliche Programm fest mit einkopiliert werden muss) die ein paar der Funktionen eines OS anbietet (wie z.B. preemptives Multitasking oder einfache Kommunikationsmechanismen) macht auf CPUs wie dem AVR einfach keinen Sinn.

Ich kenne keine 8-Bit-CPU, die ausschließlich 8-Bit hat, also mit 8-Bit-Opcodes und 8-Bit-Registern und 8-Bit-Daten.
Ich auch nicht, also lassen wir das einfach so wie es ist. ;)


Hm, auf einer 8-Bit-CPU noch von Words statt einfach Bytes zu reden fühlt sich irgendwie auch ein bisschen schräg an.
Wenn "Word" im Sinne von "kleinste adressierbare Einheit" gemeint ist ergibt das durchaus Sinn. Für Audio gab es mal spezielle DSPs die 64kWords adressieren konnten aber diese Words immer 24Bit groß waren oder denke an die 4Bit-CPUs für Taschenrechner u.ä.


Grüße
Erik
17
Offtopic / Re: Logisim CPU
« am: 11. January 2013, 20:13 »
Hallo,


Nun wenn ich jetzt in einem Befehl einen 16 bit wert in den ram laden möchte
Du meinst eine Konstante direkt in den Speicher schreiben? Welchem Zweck sollte so ein Befehl dienen? Ich kenne außer x86 keine CPU die sowas kann (obwohl, wimre kann die PDP-11 sowas auch), zumindest kenne ich keine RISC-CPU die sowas kann.

Es reicht wenn Du den Inhalt eines beliebigen Registers möglichst flexibel in den Speicher schreiben oder aus diesem laden kannst, also u.a. mit einer Adresse in der Form [r8 +/- Konstante]. Dazu musst Du auch nur 2 Register und den Befehl ansich in 16 Bit unterbringen und das sollte wirklich kein Problem sein.


@Svenska:
Ich weiß das es sowas gibt, aber ich muss auch ehrlich sagen das ein System das bis zu 1 MB RAM verwalten kann IMHO bei weitem kein reines 8Bit-System mehr ist. Selbst wenn eine CPU nur mit maximal 8 Bit Werten rechnen kann bin ich der Meinung das wenn diese in der Lage ist nativ mit 16 Bit-Adressen umzugehen ist sie zumindest ein 8Bit/16Bit-Hybrid. Das trifft IMHO auch auf die kleinen AVRs zu, die einzigsten µC die mir spontan einfallen die echte 8 Bit-CPUs enthalten sind die kleinen PICs von Microchip (und sebst für diese gibt es Librarys die z.B. preemptives Multitasking anbieten aber die kann man meiner persönlichen Meinung nach noch nicht als OS bezeichnen).


Grüße
Erik
18
Offtopic / Re: Logisim CPU
« am: 10. January 2013, 22:05 »
Hallo Tufelix,


Nun in Logisim gibts ja das Multiplizierer- und Dividierer-Bauteil (bei denen legt man einfach 2 werte an die eingäge und ohne takt bzw verzögerung wird das ergebniss an den ausgang angelegt und bleibt solange bestehen bis die werte am eingang sich verändern), die wollte ich in die ALU mit einbauen.
Dann bau die beiden Befehle mit ein. Falls Du diese CPU später mal in einem echten FPGA haben möchtest dann ist die Multiplikation (wie schon geschrieben) kein Problem und für die Division kann ich Dir gerne ein wenig voll parametrierbaren VHDL-Code geben.

Und ich stell negative Zahlen meistens im Zweierkomplement dar.
Ja, der ist wirklich gut, ich hab fast unterm Tisch gelegen!
Im Ernst, nimm Zweierkomplement so wie alle anderen auch. Die mathematischen Bibliotheken für VHDL können wimre mit Einerkomplement gar nicht umgehen und nen vernünftigen Addierer/Subtrahierer für Einerkomplement dürfte man in normalen FPGAs auch nur schwer schaffen. Außerdem verlassen sich viele C-Programmierer unbewusst auf das Zweierkomplement wenn diese mit -1 anstatt ~0 (oder noch korrekter 0xFFFFF...) vergleichen um zu prüfen ob alle Bits gesetzt sind.
Wichtigstes Argument: die Rechtschreibprüfung im Firefox kennt das Wort "Einerkomplement" gar nicht, im Gegensatz zu Zweierkomplement. ;) SCNR

Nun ich eigentlich nur fünf, JE, JG, JGE, JL und JLE.
Ich fürchte das wird nicht reichen. Da fehlt zumindest ein JNE (falls mal etwas nicht gleich sein soll) und für die anderen 4 fehlen noch 4 weitere Varianten für unsigned (JA/JAE/JB/JBE) und eventuell noch die Varianten zum direkten testen der anderen Flagbits (mit JE/JNE prüft man nur das Z-Flag). Du solltest Dir generell mal das Zusammenspiel der klassischen 4 Flagbits und der zugehörigen 14 Bedingungen ansehen (bei x86 gibt es noch zusätzlich das exotische Parity-Bit und eben 16 Bedingungen aber das muss kein Vorbild sein). Auch solltest Du Dich mal damit beschäftigen wie die verschiedenen Rechenbefehle die Flags setzen und wie man daraus Rückschlüsse auf signed und unsigned ziehen kann.

Und sie sollten mit Registervergleichen arbeiten, will daher diese Jump-Einheit einbauen.
Falls Du damit meinst das Du direkt den Inhalt von zwei beliebigen Registern vergleichen willst (oder einem beliebigen Register und ner kleinen Auswahl an Konstanten wie +1/0/-1) dann finde ich das ne ganz tolle Idee, damit könntest Du die Flags gleich komplett sparen und würdest eine Engstelle bei den Abhängigkeiten zwischen den Befehlen beseitigen.

Mhh ich glaub ich bau diese Pop und Push befehl ein.
Also ich persönlich rate davon ab aber das hatte ich ja schon erklärt.

Nun hab an 16 bit gedacht und die Befehle feste 32 bit breite.
Cooool, da kannst Du ja bei den Befehlen aus dem Vollen schöpfen. Dann solltest Du bei der Anzahl der Register lieber ein klein wenig großzügiger sein. Da Du so in 16 OpCode-Bits immer den Befehl ansich und noch 2 Register unterbringen kannst sollten alle Befehle die mit Konstanten arbeiten diese auch immer mit voller 16Bit-Größe enthalten können.
Sei froh das Du mit dieser CPU kein Geld verdienen musst, ökonomisch dürfte das nicht werden. ;)

naja welche Flags brauch ich den?
Wenn Du wirklich bedingte Sprünge baust die den Vergleich mit enthalten dann gar keine, ansonsten die üblichen 4.

Welche Vor und nach Teile hat eigentlich so ne 16 bit architektur im gegensatz zu 8 bit?
Kostet mehr Geld (also Transistoren auf echtem Silizium) und kann mehr leisten. Auf ner winzigen 8Bit-CPU würde ich erst gar nicht anfangen etwas zu programmieren das man hinterher als OS bezeichnen möchte, ja ich weiß das es sowas gibt aber mit einem richtigen OS hat das meiner persönlichen Meinung nach noch nicht viel zu tun sondern ist eher ne Art Runtime-Library.


Grüße
Erik
19
Offtopic / Re: Logisim CPU
« am: 10. January 2013, 19:08 »
Hallo Tufelix,


beim Gestalten eines Befehlssatz gibt es eine Menge zu beachten.

Ein MOV-Befehl zum Kopieren zwischen 2 beliebigen Register ist logisch, die grundlegenden Rechenarten (ADD/SUB/AND/OR/XOR) auch. ADDC/SUBC sind eine Überlegung wert (man bräuchte dafür in der eigentlichen Ausführungseinheit auch keine extra Logik sondern am Addierer/Subtrahierer eben nur noch einen Carry-Eingang der beim normalen ADD/SUB mit 0 beschickt wird) um einigermaßen Effizient mit Integer-Zahlen umgehen zu können die größer als die native Wortbreite sind. Auf Schiebe-Befehle würde ich auf gar keinen Fall verzichten da sich diese nur ganz schlecht nachbauen lassen, Du solltest auch alle 4 wichtigen Schiebeoperatoren berücksichtigen: SHL/SHR/SAR/ROL. Falls Du mehr als 8Bit breite Register hast solltest Du auch darüber nachdenken wie all die Rechenbefehle mit verschiedenen Bitbreiten umgehen können sollen (auf meiner CPU haben all diese Befehle ein Size-Attribut das angibt ob der Befehl mit 8, 16, 32 oder 64 Bit arbeiten soll, in Wirklichkeit arbeiten die Rechenbefehle aber immer mit der vollen Registerbreite (und speichern das auch immer vollständig im Zielregister ab) und nur bei der Generierung der Flags wird das dann korrekt beachtet, die Schiebe-Befehle arbeiten natürlich immer mit der gewünschten Anzahl an Datenbits). Falls Deine CPU nur ein einziges Flagset hat wäre es eine Überlegung wert ob Du all den Rechen/Schiebe-Befehlen ein Bit im OpCode spendierst mit dem bestimmt werden kann ob die Flags von dem Befehl überhaupt manipuliert werden sollen so das ein Rechenbefehl bei dem die Flags nicht weiter benötigt werden diese auch nicht zwangsweise überschreiben muss, bei ARM und MIPS (und wimre auch PowerPC) wird das so gemacht.
Auf Multiplikation und Division würde ich bei der OpCode-Gestalltung erst mal nicht verzichten, ob Du diese Befehle dann später auch realisierst ist aber noch eine andere Frage. Falls Du Deine CPU mal in einem FPGA realisieren möchtest dann geht das in VHDL ganz einfach mit dem Operator * (so wie in C auch) ohne das Du da was selber bauen musst (und da die meisten aktuellen FPGAs über Hardware-Multiplizierer verfügen sollte auch dieser Befehl in einem Takt gehen) aber für die Division wird das schon etwas komplexer. Bei diesen beiden Befehlen ist es auch von Vorteil wenn es jeweils zwei Varianten gibt die mit einem doppelt breitem Produkt/Dividend umgehen können (jeweils einmal als signed und einmal als unsigned). Bei der kleinen Multiplikation, deren Produkt genau so viele Bits hat wie die beiden Faktoren, brauchst Du nicht zwischen signed und unsigned unterscheiden da die untere Hälfte beim Produkt immer gleich ist.

Speicherzugriffe sind auf jeden Fall auch sehr wichtig aber hier würde ich mich auf ein LOAD und ein STORE beschränken diese aber dafür mit leistungsfähigen Adressierungsarten ausstatten (der Compiler Deiner Wahl wird dafür mal sehr dankbar sein). Hier sind vor allen Pre/Post-Inkrement/Dekrement (also wirklich alle 4 Kombinationen) wichtig aber auch [Adress-Register +/- beliebiges-Register] und [Adressregister +/- feste-Zahl] (diese feste Zahl muss nicht die volle Größe haben da die meisten Strukturen und Klassen nur relativ klein sind, falls diese feste Zahl vorzeichenbehaftet im OpCode gespeichert ist benötigst Du nur + oder - zur Adressberechnung). Wichtig ist bei den Speicherzugriffen aber auch wieder das die Befehle ein Parameter für die benötigte Datenbreite haben und bei den Lese-Befehle wäre noch ein Bit im OpCode wichtig das angibt ob der obere Rest im Register mit 0-Bits oder vorzeichenkorrekt aufgefüllt werden soll. Ich würde generell nicht empfehlen das man auf Register nur teilweise schreiben kann sondern eher das alle Befehle die Zielregister immer komplett beschreiben dazu musst Du nur klar definieren mit was. Wenn Du das alles ordentlich hinbekommst kannst Du auf PUSH und POP als zusätzliche Befehle verzichten, das sind dann einfach nur STORE und LOAD mit jeweils der passenden Adressierungsart.

Ein anderer Punkt sind Befehle die beliebige Konstanten in die Register laden und ob bei Deinen Rechenbefehlen einer der Parameter gegen ein Konstante austauschbar sein soll (in der Art von R4 := R8 + 479). Hier muss vor allem überlegt werden wie (mit wie vielen Bits) diese Konstanten im Befehl kodiert sein sollen.


Alle anderen wichtigen Punkte bezüglich des Befehlssatz hat Svenska ja schon genannt.

Du wärst damit bei etwa 30 Befehlen als minimale Ausbaustufe. Das ist noch nicht allzu komplex und sollte den Aufwand für den Decoder in Grenzen halten.
Auf einen Software-Interrupt (aka SYSCALL) würde ich nicht gerne verzichten da somit zumindest die Programme nicht wissen müssen wo das OS im Speicher liegt aber zu Not geht es auch mit einem CALL auf eine feste Adresse.


Es gibt aber noch ein paar Aspekte drum herum, wie z.B. :
- Wie breit soll Deine Architektur überhaupt sein?
- Wie breit sollen Deine Befehle sein? Immer mit fester Breite oder flexibel?
- Wo sind die Flags untergebracht (falls es welche gibt)?


Grüße
Erik
20
Offtopic / Re: Logisim CPU
« am: 08. January 2013, 23:28 »
Hallo,


Wird dein Projekt jetzt eher ein µC (also mit Ports) oder ein µP (also mit Bus)?
Und wo ist da für die eigentliche CPU der Unterschied?
Der CPU ansich ist es doch egal ob sie mit der Peripherie auf einem Stück Silizium untergebracht ist (und der Bus nicht nach außen geführt wird) oder ob der Bus nach außen geführt wird so das man beliebige externe Peripherie anschließen kann. Auch Mischformen sind möglich.


@Tufelix:
Konzentriere Dich erst mal auf Deine CPU, die Peripherie kommt später dran. Immer schön Schritt für Schritt und bloß keinen Vielfrontenkrieg anzetteln.


Grüße
Erik
Seiten: [1] 2 3 ... 64

Einloggen