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] 4 5 ... 64
41
Offtopic / Re: binäre Division
« am: 30. December 2012, 21:32 »
Hallo,


ich schätze mal das Deine speziellen Fragen hier etwas ungünstig platziert sein könnten. Ich selber habe noch keine Designs für echte CMOS-ICs gemacht und kenne da auch kaum Leute, ich weiß aber aus zuverlässiger Quelle das die großen Firmen (wie AMD/Intel/NVidia/....) alle VHDL oder Verilog benutzen. Wenn Du bei ARM eine richtige Core-Lizenz kaufst (was sicher mindestens einen 7-stelligen Euro-Betrag erfordert) bekommst Du auch "nur" Verilog-Quell-Code geliefert (zusammen mit ein paar Scripten und etwas nicht synthesefähigen Verilog-Code (der eine fiktive Umgebung für den CPU-Core bildet) für eine Simulation in ModelSim). Hardware noch auf Basis von Gattern oder gar Transistoren zu designen ist seit mehr als 30 Jahren old-fashioned.

Falls Du keine eigene IC-Fertigung betreiben möchtest wird das ganze darauf hinauslaufen das Du Deinen Quell-Code (VHDL oder Verilog) mit den Tools des Auftragsfertigers (also einer Foundry wie TSMC) "synthetisierst" und dieses Ergebnis dann bei der Foundry selber noch auf das Silizium Layoutet (Placing und Routing) wird. Die Tools für FPGAs machen das ähnlich: die synthetisieren erst den Quell-Code indem die gewünschte Funktionalität auf die Logik-Elemente des FPGAs abgebildet wird (das Ergebnis ist hier manchmal eine Netzliste im EDIF-Format) und im zweiten Schritt werden diese Logik-Elemente dann im FPGA platziert und dazu die Verbindungen durch die im FPGA fest vorhandene aber flexible Verbindungsmatrix gerouted. Die Tools der Foundrys sind auch alle ganz speziell auf den konkreten Herstellungsprozess den diese Foundry benutzt optimiert, da gibt es keinerlei Kompatibilität und mWn auch nichts generisches. Die Portabilität entsteht durch passend geschriebenen VHDL/Verilog-Quell-Code (ich behaupte mal das man große Teile des VHDL-Codes den ich in den letzten 10 Jahren geschrieben hab auf allen FPGAs und auch auf echten CMOS-ICs mit verschiedenen Herstellungstechnologien umsetzen könnte, mit einer maximalen Taktrate die dem jeweiligen FPGA bzw. Herstellungsprozess entspricht).

Simuliert wird digitale Logik auch üblicherweise nicht auf analogem Niveau (wo jedes Signal echte Anstiegszeiten usw. hat) sondern einfach mit passenden Laufzeiten wo der neue Pegel einfach erst nach einer gewissen Zeit (inklusive Reserve für schwankende Temperaturen, Versorgungsspannungen und Fertigungstoleranzen) ankommt und vorher noch der alte Pegel anliegt. Falls Du wirklich vor hast mal etwas im Umfeld der IC-Entwicklung zu machen solltest Du Dir zuvor mal das Entwickeln mit FPGAs genauer anschauen, wenn Du möchtest kann ich dazu gerne noch ein paar Dinge schreiben.

Das man mit gEDA auch ICs designen kann ist mir neu, ich habe damit bisher nur normale Schaltungen und passende Leiterplatten gemacht, OrCAD fällt wimre in die selbe Kategorie, von allen anderen von Dir genannten Tools habe ich noch nie gehört (trotz fast 15 Jahren Berufserfahrung in der Industrie).


Was genau ist Dein eigentliches Ziel?


Grüße
Erik
42
Softwareentwicklung / Re: Pixel ansteuern im Long Mode
« am: 18. December 2012, 20:45 »
Hallo,


... und bin über den VESA gestolpert, aber dieser benötigt ja trotzdem das BIOS und auf das kann ich ja im Long Mode nicht mehr zugreifen.
Exakt, es gibt aber auch eine VBE-Variante die im 32Bit-Protected-Mode läuft und das sollte doch im Long-Mode noch möglich sein.

Was gibt es denn als Alternative oder wie benutzt man in im Long Mode.
Eine Emulation des Real-Mode. Wimre gibt es gerade für den Zweck mal einen BIOS-Int (in Deinem Fall eben einen VBE-Int) aufzurufen extra Emulatoren die alle I/O-Zugriffe usw. an die echte Hardware weitergeben können. Die bessere Alternative wäre es natürlich einen richtigen Treiber zu schrieben aber das vereiteln die GPU-Hersteller leider sehr effektiv.

Welche Auflösung und Farbtiefe ist denn in diesem Modus möglich?
Alle die Deine Hardware kann, in meinem Laptop ist da z.B. auch die native Auflösung des Displays mit dabei. Du musst nur Code schreiben der in der Lage ist die komplette Liste der unterstützten Modi auszulesen und dann einen passenden Modus auszuwählen. Aber Vorsicht, in den Mode-Infos stehen auch Dinge drin wie der Video-RAM angesteuert wird und deswegen tauchen alle Modi mehrfach auf mit teilweise recht subtilen Unterschieden, also Dein Code muss bei der Auswahl sehr genau vorgehen.


Grüße
Erik
43
Offtopic / Re: Das war's - verabschieden wir uns vom 80386.
« am: 17. December 2012, 18:30 »
Hallo,


selbst der erste 8086 war bereits voll SMP-fähig (wurde auch in realer Hardware umgesetzt), dafür gab es das Lock-Signal und im x86-Befehlssatz das Lock-Präfix das meines (verblassten) Wissens nach mit allen Befehlen die auf den Speicher zugreifen nutzbar ist. Der Vorteil von XCHG ist der das dieser Befehl das Lock-Präfix implizit immer dabei hat (spart eben ein Byte) und bei modernen CPUs manchmal auch das Cache-Kohärenz-Protokoll etwas abkürzen kann. Die neuen Befehle des 486er bieten einfach nur ein bisschen mehr Bequemlichkeit und Performance aber keinen echten funktionalen Fortschritt.


Grüße
Erik
44
Offtopic / Re: A Guide to Kernel Exploitation, Attacking the Core
« am: 17. December 2012, 18:18 »
Aber falls jemand ein OS hat, das weit genug ist, dass es anständige Programme ausführen kann, und er meint, es sei sicher genug, kann er es ja mal als Herausforderung posten.
Wenn ich soweit bin komme ich gerne darauf zurück. ;)
45
Offtopic / Re: Logisim CPU
« am: 17. December 2012, 18:15 »
Hallo Tufelix,


Oje  :-(, was ist den genau an meinem konzept falsch?
Ich glaube ebenfalls das Deine Vorstellung davon wie Hardware funktioniert noch nicht so ganz richtig ist, ebenso von dem Zusammenspiel zwischen Software und Hardware.

Keine Hardware-Komponente hat eine exklusive Verbindung zur CPU, ist spätestens bei mehreren CPUs auch Unsinn. Ein Bussystem in einem Computer stellt die Verbindung zwischen 2 Komponenten immer nur für eine kurze Zeit her damit diese 2 Komponenten eine kleine Hand voll Daten in eine der beiden Richtungen austauschen können. Ein solcher Austausch wird üblicherweise Transfer genannt und stellt einen in sich abgeschlossenen Lesezugriff oder Schreibzugriff dar (pro Zugriff kann aber mehr als ein Byte oder ein Word übertragen werden, das nennt sich dann Burst oder Block-Transfer). Für alles was komplexer ist werden mehrere unabhängige Transfers benutzt (wo dazwischen sogar der Bus von anderen Komponenten benutzt werden kann). In dem von Dir verlinkten Wikipedia-Artikel gibt es gar keine Beschreibung wie ein Datenbus in einem Computer im Detail funktioniert, dafür ist dort der NuBus verlinkt und in dessen Wikipedia-Artikel ist die zugehörige Spezifikation verlinkt. Das sind relativ wenige Seiten Text und der NuBus ist vom Feature-Umfang noch recht überschaubar und würde ungefähr das bieten was Du aktuell brauchst (was jetzt keine Aufforderung sein soll diesen Bus umzusetzen sondern das ist nur ein Hinweis auf eine Technologie in ungefähr der benötigten Gewichtsklasse). Ich hab mir die Spezifikation gerade mal durchgelesen und empfinde die als einigermaßen verständlich geschrieben und es sind auch keine zu komplexen Sachen drin (der NuBus kennt z.B. keine Bridges u.ä. so das es immer nur einen einzigen NuBus in einem System gibt was die Sache fürs erste unheimlich vereinfacht).

Ein Bussystem in einem Computer ist im Ideal absolut agnostisch gegenüber allen angeschlossenen Komponenten und auch diese Komponenten sollten möglichst agnostisch gegenüber dem Rest der Komponenten sein (außer das alle Komponenten natürlich das Protokoll auf diesem Bus beherrschen müssen wissen die üblicherweise nichts über alles was sonst noch so an diesem Bus hängt) auch die CPU interessiert sich nicht dafür was wo ist und wie diese Komponenten funktionieren (das ist Aufgabe der Software also der Gerätetreiber die ihr jeweiliges Gerät gegenüber einer generischen Schnittstelle im Betriebssystem passend darstellen), die CPU muss dazu nur Befehle wie Speicherlesen und Speicherschreiben beherrschen (und das dann natürlich mit dem richtigen Protokoll auf den Bus bringen) damit die Software das kann.


Mit einem IDE-Treiber würde ich nicht als erstes anfangen, ich würde eher die Serielle Schnittstelle als Anfang empfehlen obwohl da leider die Gefahr besteht das Du sowas gar nicht mehr in Deinem PC hast (was aber auf IDE ebenfalls zutrifft, falls Du im BIOS bereits auf AHCI-Modus umgestellt hast). Es geht natürlich auch irgendein Emulator (Qemu/VirtualBox/...) die können alle noch eine echte Serielle Schnittstelle anbieten und diese auch im Host-OS als virtuellen Port zur Verfügung stellen so das auf dem Host-System wieder ein Programm (das natürlich die API des Host-OS benutzen muss) der passende Kommunikationspartner ist.
Für den zweiten Schritt ist IDE aber eine gute Wahl wobei ich hier auch auf einen Emulator setzen würde (schon damit Du nicht aus Versehen Deine echte HDD killst).


Grüße
Erik


Vier Räder, große Fenster, viele Sitze, ... wie ein Bus halt. :roll:
Also hier in Nürnberg haben die meisten Busse mehr als 4 Räder (also auf der Straße, zusätzlich zu Lenkrad und Reserverad). Dafür sind die Fenster nur noch eingeschränkt nutzbar da die von Außen mit Spam zugekleistert sind.
SCNR
46
Lyrisches Eck / Re: Ubuntu und Windows
« am: 06. December 2012, 10:47 »
Hallo,


Da z.B. XFS aber ohne "PC" im Hinterkopf entwickelt wurde, geht das dafür nicht.
Wimre war XFS laut der GRUB-Doku möglich aber meine Notfall-CD hatte kein geeignetes fsck.xfs dabei so das ich deswegen kein XFS genommen habe, aber ich glaube mich zu erinnern das ein Testlauf mit XFS erfolgreich war (ich hab jedenfalls etliche Dateisysteme durchprobiert (einige erfolgreich) und nur JFS war in allen Aspekten eine überzeugende Wahl).

Mit FAT und NTFS allerdings nur, wenn die CPU auch x86-Befehle ausführen kann.
Ich bin mir ziemlich sicher das man auch Code für andere CPUs in den Boot-Sektor von FAT/NTFS legen kann, das einzigste was die CPU dafür können muss ist ein JMP-Befehl der 30 bis 50 Bytes überspringen kann und maximal 3 Bytes belegt (wobei ich persönlich keine Hemmungen hätte das Feld "OEM-Name" einfach mit Programm-Code zu überbügeln) und daran dürften die meisten RISC-CPUs scheitern (hier muss man ganz klar sagen das MS und IBM vor über 30 Jahren leider nicht an heutige CPUs gedacht haben) aber sowas wie 68k und viele andere CISC-CPUS auch müssten das problemlos schaffen. Das echte Problem dürfte eher sein das diesem Code irgendeine genormte Umgebung wie z.B. die BIOS-Interrupts zur Verfügung stehen muss (für Dinge wie Sektor-Lesen oder Konsolen-Output) und sowas funktioniert in der Realität nur wenn ein Schwergewicht wie IBM das definiert und durchsetzt.

Das war vermutlich der OS/2 Bootmanager.
Nein, ganz sicher nicht. Ich erinnere mich genau das ich für diesen BootLoader eine extra Installation/Reparatur-Diskette hatte (mit der man bei Problemen den BootLoader in einer tollen Oberfläche wirklich anständig wieder flott kriegen konnte) und die war von irgendeiner anderen Firma.
Ich kann mich gar nicht erinnern das OS/2 einen BootLoader hatte, hm naja, ist schon lange her.


Grüße
Erik
47
Offtopic / Re: Logisim CPU
« am: 06. December 2012, 00:08 »
Hallo,


Nun wie funktioniert eigentlich so ein Busmaster?
Das ist im wesentlichen eine Bridge die zwischen der internen Art wie die CPU auf Speicher zugreift in das Protokoll übersetzt welches auf dem externen Bus benutzt wird.
Schau Dir doch mal an wie die Klassiker wie ISA o.ä. funktionieren.
Zu den CPUs aus der Altersgruppe 386 und 486 gibt es im iNetz bestimmt eine ansprechende Beschreibung wie ein ordentlicher 32Bit-Bus funktioniert.
Und wenn Du dann das Niveau "fortgeschritten" erreicht hast ist PCI oder besser PCI-Express auch eine interessante Lektüre ;) (mal davon abgesehen das diese Spezifikationen nicht frei erhältlich sind, aber die iNetz-Suchmaschine Deines persönlich geringsten Misstrauens kann Dir bestimmt weiterhelfen, ansonsten ist Hypertransport guter Lesestoff, aber Vorsicht: alle diese Specs haben etliche hundert Seiten).

edit:
Für den Anfang ist aber z.B. der 8Bit-AVR eine gute Vorlage, wimre gab es auch dort Versionen die externen SRAM (und auch passende MMIO-Hardware) anbinden können. Üblicherweise liefert Atmel sehr gute (und frei verfügbare) Datenblätter in denen bestimmt sehr anschaulich beschrieben ist wie dieser externe Bus arbeitet also wie ein Zugriff auf externen Speicher abläuft und wie das vom CPU-Kern benutzt wird.


... musst du eine Busarbitrierung haben. Das kannst du mit zwei Leitungen machen: BUSREQ/BUSACK.
Fast richtig, jedes busmasterfähige Gerät benötigt natürlich ein eigenes BUSREQ/BUSACK-Pärchen. SCNR
Theoretisch kann man sogar diese Arbitrierungslogik als eigenständige Komponente bauen und die CPU benötigt dann ebenfalls BUSREQ/BUSACK um den Bus bekommen zu können (aber üblicherweise wird die Arbitrierungslogik einfach in die CPU integriert und deren BUSREQ/BUSACK-Leitungen gehen nur im Chip vom CPU-Kern zum Arbiter). Bei besseren Systemen berücksichtigt der Arbiter auch Prioritäten damit z.B. die CPU nicht so lange warten muss bis sie mal wieder ran darf aber fürs erste geht es auch ohne solche Extras.


Grüße
Erik
48
Offtopic / Re: Logisim CPU
« am: 05. December 2012, 18:40 »
Hallo Tufelix,


Nun ich hab jetzt mein konzept wieder einmal verbessert.
Ja, also die Richtung stimmt schon mal, nur weiter so.

Das "JUMP" zwei Register vergleichen kann ist recht gut, auf diese Weise kannst Du Dinge wie "if (a > b) then ..." ziemlich effizient umsetzen und kannst Dir die Flags komplett sparen. Wimre waren in der offiziellen Spec der ALPHA-CPU sogar einige Beispiele drin wie man sowas geschickt einsetzen kann, das ist zwar eher für Compiler-Programmierer interessant aber dürfte einen angehenden CPU-Entwickler sicher auch nicht schaden.

Wozu der Programm-Counter zweimal vorhanden ist (einmal einzeln oben rechts und einmal im Registerfile unten) verstehe ich nicht. Du kannst den aktuellen Programm-Counter durchaus als "normales" Register anbieten aber er sollte trotzdem nur an einem Ort gespeichert sein. Wenn der Programm-Counter als normales Register ansprechbar ist musst Du erstmal definieren was für einen Wert ein Befehl daraus lesen kann, z.B. seine eigene Adresse (das ist super toll für positionsunabhängigen Code und ein paar andere Nettigkeiten). Auch musst Du definieren was passieren soll wenn auf dieses Register geschrieben wird, z.B. das die Pipe-Line geleert werden soll und an der neuen Adresse im ROM weiter gearbeitet wird womit Du nahezu jeden Rechenbefehl als JUMP benutzen kannst und z.B. ein simpler "MOV ProgCount,LinkReg" als RET-Befehl funktioniert (spart Dir wertvolle OpCode-Bits ein da es so keinen eigenständigen RET-Befehl gibt). Außerdem ist dann ein unbedingter JUMP nur ein "LI ProgCount,&Label" (also ein normaler Load-Imediate den Du eh brauchst um Konstanten in ein beliebiges Register zu laden).

Das Du I/O als RAM bauen möchtest verstehe ich nicht, bei mancher Hardware ist so ein I/O-Register gar kein echtes Speicherelement sondern der Schreibzugriff startet einfach nur eine Aktion in der Hardware welche durch den übermittelten Wert selektiert wird (also eine Art Commando-Port, Lesezugriffe auf diesen Port liefern oft nichts oder einen reinen Status-Wert). Ich würde Dir doch noch mal empfehlen an die Stelle von RAM und I/O einen richtigen Bus-Master zu setzen der dann mit seinem Bus eben RAM aber auch beliebige Memory-Mapped-Hardware ansprechen kann.


Grüße
Erik
49
Lyrisches Eck / Re: Ubuntu und Windows
« am: 05. December 2012, 11:04 »
Hallo,


Mehrere MBRs können nicht miteinander koexistieren ...
Richtig, aber wenn der MBR der vorhanden ist sich einfach an die seit über 30 Jahren für den PC (da ein MBR ausführbaren Code enthält kann er zwangsläufig nicht plattformübergreifend sein) gültige Konvention hält (so wie der von MS es tut) dann können damit auch alle Dateisysteme gebootet werden die sich ebenfalls an diese Konvention halten.
Mein Linux (Kubuntu 10.04) liegt hier in einer Partition mit JFS, das OpenSUSE vorher lag in einem RiserFS (wimre v3) und es funktionieren auch noch einige andere Dateisysteme. Eigentlich sollte die ext-Familie das auch unterstützen aber das habe ich damals (wo ich etliche Abende gebraucht hatte um mein heutiges Kubuntu zu installieren) einfach nicht hinbekommen weiß aber heute leider nicht mehr woran das genau lag (wimre hat grub-install eine erfolgreiche Installation in ext3 gemeldet aber funktioniert hat es trotzdem nicht, mein MBR hat nichts bootfähiges gefunden und auch per Diskeditor sah das nicht gut aus).

Darum muss jedes Betriebssystem den MBR überschreiben, um die eigene Bootbarkeit zu garantieren.
Naja, das Wort "muss" würde ich dafür nicht benutzen aber im DAU-Modus tut das Installationsprogramm erstmal nichts falsches wenn es zumindest die bootbarkeit des eigenen OS auf diese Art sicher stellt, wohingegen im Experten-Modus eine Frage ob der vorhandene MBR tauglich ist und unangetastet bleiben soll schon sehr angebracht wäre (OpenSUSE 9.? hat das vor etwa 5 Jahren zu meiner vollsten Zufriedenheit anständig so erledigt und sich ohne Probleme komplett mit BootLoader in seine Partition installiert ohne den Rest der Platte auch nur anzufassen).

Ein naiver MBR, wie der von Microsoft, kann nicht jedes Dateisystem booten.
Bei mir hat der MBR von Windows XP problemlos Linux (also GRUB) gebootet (sowohl aus JFS als auch aus RiserFS). Ich hab den aus Neugierde sogar mal disassembliert und der hält sich meiner Meinung nach sehr gut an die PC-Konvention.

Da UEFI mit mehreren Architekturen im Kopf entwickelt wurde, schreibt es eine FAT-Hilfspartition vor, die alle Bootloader enthält.
Meiner Meinung nach einer der wenigen echten Pluspunkte von UEFI, vor allem zusammen mit dem neuen Partitionierungsschema.

Da Partitionen (historisch) nur an Zylindergrenzen beginnen dürfen, ist der Bereich zwischen MBR und dem zweiten Zylinder garantiert unbenutzt und wurde "schon immer"(TM) für Universalbootloader (PQBoot, XFDisk u.a.) benutzt.
Das mit der Historie ist zwar richtig aber spätestens seit die Platten die 8GB-Grenze durchstoßen hatten und die C/H/S-Angaben im MBR obsolet wurden ist das nur noch eine unnütze Tradition. Eine Pflicht war das übrigens auch vorher schon nicht, selbst zu DOS-Zeiten (auf einer 120MB-Platte, ja so alt bin ich schon ;) ) war ich schon zu geizig diese 31 kB einfach brach liegen zu lassen und hatte weder mit DOS noch später mit Windows NT oder OS/2 oder SUSE 6.? damit irgendwelche Probleme, nur das fdisk von Linux hat über die "unausgerichteten" Partitionen gemeckert aber trotzdem korrekt gearbeitet. Ich hatte damals auch einen extra Boot-Loader (Name weiß ich leider nicht mehr) der zwischen all diesen OSen wählen konnte und der lag ganz sicher in einer extra Partition die sogar eine erweiterte Partition sein durfte. Dessen MBR war in der Lage anhand des Partition-Typs der als bootfähig markierten Partition zu entscheiden ob dort wieder eine neue Tabelle liegt (und er wieder neu suchen muss) oder er den Sektor nun anspringen sollte. Mit diesem MBR konnte ich auch OS/2 und Windows NT direkt starten obwohl diese in erweiterten Partitionen lagen (nur DOS und Linux hatten primäre Partitionen aber ich bin mir sicher das zumindest auch Linux aus einer erweiterten Partitionen gebootet hätte).


Grüße
Erik
50
Lyrisches Eck / Re: Ubuntu und Windows
« am: 04. December 2012, 20:34 »
Hallo,


wird aber wahrscheinlich größere Änderungen erfordern da in den ersten 512Byte ja schon die passenden Dateisystemtreiber enthalten sein müssten
als ich das letzte mal in den Quell-Code von GRUB reingesehen hab war in den ersten 512 Bytes nur eine Sektor-Liste für Stage 1.5 und sowas funktioniert unabhängig von der tatsächlichen Position auf dem Blockdevice. Das schwierigere Problem dürfte sein wo man innerhalb einer Partition also innerhalb eines Dateisystems mal einige kBytes Daten ablegt ohne das diese von der eigentlichen Dateiverwaltung belästigt werden (sonst müsste man diese Blockliste ja eventuell mal aktualisieren), FAT hat für sowas extra reservierte Sektoren und auch RiserFS hat so ein Feature. Alternativ kann man natürlich für jedes FS einen speziellen Bootsektor programmieren der eine vorgegebene Datei aus dem normalen Dateisystem lädt, für FAT ist das simpel und für NTFS hat Microsoft sowas offenkundig auch geschafft (aber damit mehrere Sektoren als Boot-Sektor-Erweiterung belegt). An diesem Punkt hat die Open-Source-Gemeinde dann doch mal nicht die bessere Lösung geschaffen.

Grub ist btw. nicht das einzige Programm welches den Platz zwischen MBR und Partition nutzt ...
Ja, fürchterlich solche Unsitten. Was machen diese Programme wenn es auf der Festplatte keine solchen Leerräume gibt? Ist ja schließlich kein muss. Bei mir sind alle Partitionen auf durch 16 teilbare Sektornummern ausgerichtet, so das hinter dem MBR nur 15 Sektoren frei sind und zwischen den Partitionen gar keine freien Sektoren und auch der Überhang hinter der letzten Zylindergrenze (der nur per LBA vernünftig ansprechbar ist) wird bei mir benutzt.

weitaus schlimmer als ein Bootloader, für den der Platz afaik vorgesehen ist.
Dieser Platz ist wimre explizit Niemansland und niemand darf sich darauf verlassen das diese Bereiche unangetastet bleiben. Zum speichern von Daten sind nur die Sektoren innerhalb der Partitionen vorgesehen und sonst nix.

Windows 8 legt btw. nicht automatisch eine 2. Partition an, nur wenn man BitLocker auf C: aktiviert.
Aha, ich hatte dieses Problem mal mit Windows 7 welches unbedingt 2 Partitionen haben wollte (die zweite war eine kleine FAT-Partition mit 100 MB Größe und vielleicht 5 MB Daten drin, die konnte man sogar ganz normal mounten).


Grüße
Erik
51
Offtopic / Re: Logisim CPU
« am: 04. December 2012, 19:54 »
Hallo Tufelix,


die Pipeline entsteht durch die Zwischenregister (die grünen vertikalen Blöcke), einige davon (aber nicht alle!) kannst Du problemlos weglassen und schon hat diese Pipeline weniger Stufen. Solange Du nur innerhalb eines Simulators bleibst der keine Durchlaufzeit durch die Logik hat ist das völlig in Ordnung.

In dem Wikibook gibt es doch auch Single-Clock-CPUs, schau dort mal vorbei.


Grüße
Erik
52
Lyrisches Eck / Re: Ubuntu und Windows
« am: 04. December 2012, 12:10 »
Hallo,


was ich an dieser Diskussion ein wenig vermisse ist eine korrekte Beschreibung der tatsächlichen Ursache dieses Dilemmas.
Hier ist ausnahmsweise mal nicht Windows der echte Schuldige, auch wenn es Windows durchaus übel zu nehmen ist das dieses einfach ungefragt den Programm-Code im MBR überschreibt (zumindest im Experten-Modus sollte eine entsprechende Frage kommen). Das wirkliche Problem besteht darin das Linux bzw. GRUB gegenüber dem MBR nicht agnostisch ist, im Gegensatz zu Windows. Das liegt daran das sich GRUB nicht (ohne viel Arbeit) in eine Partition installieren lässt um damit dem Konzept des Chain-Loading zugänglich zu sein, GRUB will per Default immer in den MBR und belegt auch noch unerlaubterweise die freien Sektoren zwischen dem MBR und der ersten Partition (obwohl es keine Zusicherung gibt das dort überhaupt genügend freie Sektoren vorhanden sind und es auch niemand verbietet diese nicht zugewiesenen Sektoren mit beliebigen Müll zu überschreiben). Wenn man GRUB einfach in den Boot-Sektor der entsprechenden Linux-Partition installiert und GRUB auch sonst keine Sektoren außerhalb dieser Linux-Partition belegt kann auch der Windows-BootLoader (und jeder andere BootLoader der ebenfalls Chain-Loading beherrscht) diesen GRUB laden und damit indirekt auch das darin konfigurierte Linux starten.

Auf meinem PC hab ich das genau so eingerichtet, ich habe GRUB in die (primäre) Linux-Partition installiert (was mich etliche Abende Fummelei gekostet hat) und danach Windows XP in eine andere primäre Partition installiert. Danach hab ich das Boot-Menü von Windows um einen entsprechenden Eintrag für die Linux-Partition erweitert und schon konnte ich vom Windows-BootLoader aus Linux (also GRUB) anwählen. Danach hab ich noch das Boot-Flag im MBR von der Windows-Partition auf die Linux-Partition umgeändert (was sogar mit Windows-Boardmitteln geht) damit der MBR per Default GRUB lädt (Windows ist bei mir nur zweite Wahl) und dann noch im GRUB-Menü einen Eintrag für die Windows-Partiton eingefügt. Nun kann ich von GRUB in den Windows-BootLoader wechseln und auch wieder zurück ohne tatsächlich ein OS zu starten. Das alles funktioniert mit dem MBR-Programm-Code von Windows genauso gut wie mit jedem anderen MBR-Code der sich an die althergebrachte Konvention hält.

Ich selber bevorzuge auch Linux aber diesen speziellen Punkt finde ich an Linux bzw. gängigen Distributionen ziemlich doof. GRUB beherrscht zwar durchaus Chain-Loading ist dem aber selber nur mit viel Aufwand und einigen unangenehmen Nebenwirkungen zugänglich. Hier sollte IMHO noch mal gründlich nachgebessert werden.


Ich habe auch eine Partition (ca.80GB) frei.
Ob da eine Partition reicht? IMHO belegt Windows ab 7 immer mindestens zwei Partitionen (wovon eine auch eine erweiterte sein darf).

Grüße
Erik


Was ich nicht höhren möchte ist:
Zitat
Deinstalliere das Windoof!
(oder so)
Wenn Du die einzigst richtige/vernünftige Antwort bereits kennst warum verweigerst Du Dich dieser? Sorry, aber das klingt für mich ein wenig nach "wasch mich aber mach mich nicht nass". ;)
SCNR
53
Offtopic / Re: Logisim CPU
« am: 03. December 2012, 12:03 »
Hallo Tufelix,


schau doch mal auf http://en.wikibooks.org/wiki/Microprocessor_Design/Pipelined_Processors das vierte Bild zeigt eine relativ simple RISC-Pipeline in der recht gut zu erkennen ist wie u.a. das Registerfile eingebunden ist.
(und auch ins eigentliche Buch http://en.wikibooks.org/wiki/Microprocessor_Design)

Was Du in deinem Bild mit "RAM" beschreibst sollte eine Art Bus-Master sein der einen externen Bus ansteuert an welchem dann RAM aber auch MMIO-Ports hängen können, so ein Bus benötigt nicht nur die eigentlichen Datenleitungen sondern auch Adressleitungen (die Anzahl dieser Leitungen bestimmt die Größe des Adressraums der CPU) und Steuerleitungen (um z.B. zwischen Lesen und Schreiben unterscheiden zu können). Wenn das was bei Dir mit "ROM" bezeichnet wird ein vergleichbarer Busmaster ist dann kannst Du einfach zwischen Harvard (jeder dieser Busmaster verfügt über ein eigenes System) oder von-Neuman (beide Busmaster greifen auf den selben Bus zu, was natürlich eine Arbitrierung erfordert) umbauen.


Grüße
Erik
54
Offtopic / Re: binäre Division
« am: 03. December 2012, 11:27 »
Hallo,


Mein Problem ist halt, dass die Subtraktionen voneinander abhängen und ich sie nicht parallelisieren kann.
Das ist nun mal der Kern einer jeden Division, deswegen baut man das ganze ja als getaktete State-Maschine in dem pro Takt immer nur eine (oder wenige) Bit vom Quotienten ermittelt werden und somit pro Takt auch nur eine (oder wenige aber parallele) Subtraktion erforderlich ist. Man kann natürlich auch alle diese Stufen jeweils in Hardware realisieren und ohne Zwischenregister hintereinander schalten was aber den maximalen Takt auf ein n-tel begrenzt (weil diese riesige Logik-Schaltung eine enorm lange Durchlaufzeit hat).

Dieses SRT interessiert mich, da die Operanden zuvor analysiert werden.
Falls Du nicht wirklich vor hast einen ASIC zu designen würde ich von SRT eher die Finger lassen. Der Kern von SRT geht davon aus das Du z.B. bei einer Radix-4-Division nicht immer den kompletten Divisor mit dem kompletten aktuellem Fenster des Dividenden vergleichst sondern von beidem z.B. nur die obersten 5 Bit nimmst (was auch bedeutet das man auch beim Divisor genau wissen muss wo das höchste Bit ist) und damit für die 2 Bit des Quotienten nicht nur die Werte +0...+3 sondern -1...+4 erhalten kannst da so eine Schätzung ja auch mal daneben gehen kann und dann in der nächsten Stelle korrigiert werden muss. Der Hintergedanke dazu ist das man sich gerade bei großen Bittiefen der beteiligten Zahlen versucht die doch recht lange Durchlaufzeit einer vollständigen Subtraktion zu ersparen. In Takten gerechnet würde ich vermuten (nicht wissen) das eine SRT-Division eher ein oder zwei Takte mehr benötigt (wegen komplexerer Vorbereitungen und Nachbereitungen) aber dafür z.B. 20% höheren Takt ermöglicht weil die Subtraktionen in der eigentlichen Kernschleife abgekürzt werden, bei 128Bit : 64Bit und Radix-4 lohnt sich das durchaus (in absoluter Zeit gerechnet) da die 2 Zusatztakte nicht mal 10% von den 32 Takten für die Kernschleife ausmachen. Dafür dürfte der Transistorbedarf deutlich höher liegen (ich schätze mal mindestens das doppelte) und auch das Design ist enorm komplexer (und fehleranfälliger wie Intel vorgemacht hat) da Du überlegen musst wie viele Stellen des Quotienten Du pro Takt korrigieren kannst und diese Schätzfunktion (anstelle eines korrekten Vergleichs) ist sicher auch nicht ganz ohne. Auch wenn Du Deine Logik einmal in einem FPGA realisieren möchtest würde ich von SRT abraten da FPGAs üblicherweise über Carry-Chains verfügen mit denen sich auch breite Subtraktionen/Additionen/Vergleiche relativ performant umsetzen lassen, in einer Soft-CPU in einem FPGA ist eine Subtraktionen mit voller Bitbreite sicher nicht der kritische Pfad der den maximalen Takt limitiert. SRT lohnt sich IMHO nur bei echten CPUs wo man vermeiden möchte das die Division den maximalen Takt zu stark limitiert und man deswegen gerne ein paar Transistoren mehr auf das Silizium verteilt wenn man dafür die Konkurrenz wieder mal überholen kann.

Alles in allem scheint die Division eine teure Angelegenheit zu werden.
Ja, das hast Du absolut korrekt erkannt. ;)


Grüße
Erik
55
Offtopic / Re: binäre Division
« am: 02. December 2012, 17:27 »
Hallo Dimension,


eine Frage vorweg: Integer oder Floating-Point?
Die Newton-Raphson Division ist eher für Floating-Point ausgelegt da das Reziprok des Divisors ja kleiner als 1.0 ist falls der Divisor größer 1.0 ist ansonsten natürlich umgedreht (Newton-Raphson kommt mit beidem gleich gut zurecht).

Falls Du Integer meinst lässt sich die schriftliche Division eigentlich ziemlich effizient (was Flächenbedarf pro Performance angeht) in Hardware implementieren.
Wichtig ist das Du im ersten Schritt alle Sonderfälle wegschaffst: Divisor==0 und Dividend<Divisor*2.
Außerdem musst Du zur Vorbereitung noch ermitteln um wie viele Bits der Divisor für den ersten Schritt tatsächlich nach links geshiftet werden muss (also wo wahrscheinlich das höchste Bit im Quotient steht).

Bei einer Hardwareumsetzung würde ich aber nicht den Divisor shiften sondern den Dividend.
Beschleunigen lässt sich das Ganze indem pro Takt nicht nur ein Bit vom Quotienten sondern z.B. 2 Bits ermittelt werden, dazu wird der Inhalt des aktuellen Fensters vom Dividend nicht nur mit dem Divisor verglichen sondern parallel auch mit Divisor*2 und Divisor*3 (das kostet nur 2 zusätzliche Vergleicher dafür musst Du alle anderen Shift-Operationen und auch die Vorbereitungsopertionen auf vielfache von 2 ausrichten). Wenn als zusätzliche Abbruchbedingung noch Dividend==0 (also den aktuellen bearbeiteten Dividend) vorhanden ist gehen auch Divisionen wie 100'000'000/10'000'000 in wenigen Takten durch.


Grüße
Erik
56
Offtopic / Re: Logisim CPU
« am: 02. December 2012, 14:32 »
Hallo Tufelix,


Wenn Du eine CPU bauen möchtest solltest Du vorher ein paar grundsätzliche Design-Entscheidungen treffen.

z.B.: RISC vs. CISC  oder anders:  simple Load/Modify/Store-Architektur oder was komplexeres.
CISC ermöglicht oft Befehle wie "add [ax],bx" was bedeutet das der Wert von Adresse aus AX geladen wird (in ein internes temporäres Zwischenregister das nicht explizit ansprechbar ist), dann der Wert von BX dazuaddiert wird und das Ergebnis wieder an die selbe Adresse (AX) in den Speicher zurückgeschrieben wird. Bei RISC benötigt man dazu oft 3 Befehle: "ld r3,[r1]  ;  add r3,r3,r2  ;  st [r1],r3" was bedeutet das der erste Befehl den Wert von Adresse R1 in das normale Register R3 lädt (R3 dient hier als Zwischenregister), der zweite Befehl dann R3 = R3 + R1 berechnet und der letzte Befehl das Ergebnis wieder in den Speicher schreibt. Der Hintergrund dieser Design-Entscheidung ist ob Du die Komplexität in Deine CPU packst, für die erste Variante benötigst Du eine recht komplexe State-Maschine (oft basierend auf Micro-Code), oder ob das der Compiler erledigen soll und Du dafür eine Menge Arbeit beim CPU-Design sparst. Für die zweite Variante spricht das es nur 2 Befehle geben muss die auf Speicher zugreifen können und Du gezielt dort die Komplexität von höherwertigen Speicheradressierungsmodi unterbringen kannst ohne die restlichen Befehle unnötig aufzublähen. Von der Performance sind beide Varianten etwa gleichwertig wenn man die CPU wirklich gut baut (heutige x86-CPUs setzten Befehle wie den oben genannten intern auch in mehrere Befehle um aber benötigen dafür vielfach mehr Transistoren im Decoder als z.B. eine ARM-CPU die pro Takt letztlich eine ähnliche Performance erreicht). Für den Einstieg würde ich trotzdem ganz klar RISC bevorzugen und alles was auch nur minimal komplex ist dem Compiler überlassen (der LLVM kann sowas bereits ziemlich gut).

Für den Stack benötigt man nicht unbedingt mehr als ein Register, alle modernen CPUs die das Flat-Memory-Model unterstützen kommen mit einem Register für den Stack aus. Für Hochsprachen lohnt es sich aber wenn es zusätzlich zum Stack-Pointer noch einen Frame-Pointer gibt, spätestens wenn VLA oder ähnliches unterstützt werden soll ist das sogar zwingend erforderlich. Multithreading lässt sich auch mit einem einzelnen Stack-Pointer-Register erledigen indem für jeden Thread der Stack in einem anderen Speicherbereich liegt, klar bedeutet dass das die einzelnen Stacks (von einem Prozess) nicht wirklich gegeneinander geschützt sind aber das sind sie bei allen anderen heutigen CPUs auch nicht. Interessanter ist schon eher die Design-Entscheidung ob Dein Stack nach oben oder nach unten wachsen soll (letzteres ist eher ein Relikt aus der Zeit als Programme noch grundsätzlich singlethreaded waren und es nur einen kleinen Speicherbereich gab der von unten kommend mit dem Heap und von oben kommend mit dem Stack belegt wurde wird aber trotzdem von vielen CPUs so genutzt bzw. von den Compilern so festgelegt (ARM/PowerPC/... können beides)).
Auch musst Du entscheiden ob es außer LD und ST noch Befehle wie PUSH und POP geben soll die implizit den Stack benutzen oder ob CALL/RET für die Rücksprungadresse den Stack implizit nutzen können oder ob ein extra Link-Register existieren soll. Beides hat Vorteile und Nachteile, und kann z.B. darüber entscheiden wie Aufwendig das Verschachteln von Interrupts/Exceptions wird.

Es gibt noch jede Menge anderer Design-Entscheidungen die Du treffen musst bevor Du anfangen kannst, z.B. wie Du bedingte Befehlsausführung realisieren willst (mit einem der möglichen Flag-Konzepte oder anders (siehe ALPHA)).


Auserdem will ich für das projekt einen Compiler programmieren, hat wer ne Idee wie man das am besten macht?
Da solltest Du vielleicht mal einen Blick auf den LLVM werfen. Dort gibt es auch Vorlagen für einen Assembler der dann auch Labels usw. beherrscht.


Um mal einen Überblick über die möglichen CPU-Architekturen zu bekommen empfehle ich zuerst den 8Bit-AVR und dann mal den AVR32 (für beides gibt es bei Atmel sehr gute Beschreibungen der Befehlssätze und der OpCode-Architektur). Auch die NIOS-Soft-CPU von Altera ist einen Blick wert vor allem da die Tools mit denen man daraus zusammen mit der Peripherie vollständige Systeme baut recht gut sind (und ebenfalls eine gute Doku für die Befehlsarchitektur vorhanden ist) aber das setzt Kenntnisse in der FPGA-Programmierung voraus.

Falls Du Programme von einem externen Speichermedium laden können möchtest dann ist die Harvard-Architektur IMHO nicht sehr empfehlenswert aber für die ersten Gehversuche ist das sicher keine so schlechte Wahl.


Grüße
Erik
57
Offtopic / Re: Eigene CPU
« am: 29. January 2012, 12:42 »
ich seh gerade das Dein Immedite ja nach dem Befehl kommt der dieses Immediate benutzen möchte, von daher ignoriert Bitte die erste Hälfte meines Beitrages
58
Hallo,


Meinst du denn, dass existierende Programme überhaupt die Fähigkeiten deiner Architektur ausnutzen können?
Äh, ja, also schon oft. Ich denke das alle Programme zumindest von dem Gewinn an Sicherheit mehr oder weniger profitieren können. Ein absolut fehlerfreies Programm (in dem es gar keine Buffer-Overflows usw. gibt) profitiert natürlich nicht davon aber auf wie viele Programme trifft das denn zu? Vom Geschwindigkeitsvorteil durch das (meistens) abgeschaltete Paging profitieren natürlich auch alle Programme.

Ich glaube nämlich nicht, dass du was anderes machen kannst als je ein Segment für Code, Stack und Daten anzulegen.
Das ist aber schon mehr als im klassischen Flat-Memory gemacht wird, dort liegt absolut alles (sogar der OS-Kernel) in einem einzigen Adressraum. Bei mir ist z.B. der OS-Kernel aus dem User-Mode mit wirklich gar keinem Pointer erreichbar (es gibt keine 48/80 Bit-Kombination die den Kernel aus dem User-Mode adressieren kann). Auch muss ein Programm bei mir ja nicht auf 4 Segmente (Code, Const, Data und Stack) beschränkt bleiben, ich habe z.B. vor das der Heap sich über viele Segmente verteilt. Mein malloc() wird sicher nicht jedes mal ein neues Segment erstellen (das wäre totale Speicherverschwendung, schon weil so ein Segment immer ganze Pages belegt und auch etwas an Verwaltungsdaten kostet) aber ich will für jede benutzte Objekt-Größe ein neues Segment erstellen und dieses Segment wie ein Array aus Elementen dieser Größe verwalten (die Verwaltung als Array ist auch ziemlich effizient implementierbar so das malloc und free bei mir ordentlich schnell werden).

Die Programme haben ja keine Möglichkeit mitzuteilen, wie die Daten logisch zusammenhängen.
Der logische Zusammenhang von verschiedenen Objekten braucht IMHO auch keinen Einfluss darauf haben wie diese Objekte über die Segmente verteilt sind (es wird ja überall mit FAR-Pointern gearbeitet), das einzigste was ich aber in jedem Fall vermeiden will ist das einzelne Objekte/Arrays über mehrere Segmente verteilt werden müssen (so wie im x86-RM bei Objekten/Arrays mit mehr als 64 kB) so das meine Segmente schon recht groß werden können.

Macht es überhaupt Sinn diese Programme mit mehr als diesem "Legacy-Modus" á la x86 zu unterstützen?
IMHO ja. Und selbst wenn es nur 5 Segmente sind (also der Heap nur ein einziges Segment benutzt) ist es ja schon deutlich besser als alles was Flat-Memory auch nur theoretisch anbieten kann. Dazu kommt das spätestens bei Multithreading noch mehr Vorteile zum tragen kommen: jeder Stack hat sein eigenes Segment und kann auch unabhängig von anderen Stacks wachsen so das man sich nicht schon vorher überlegen muss wie man eine potentiell unbekannte Anzahl von Stacks in den einen virtuellen Adressraum unterbringen will. Nebst dessen das für die Stacks auch immer virtueller Speicher verschwendet wird da ja nicht vorhersehbar ist welcher der Stacks eventuell etwas mehr wächst als andere. Bei Flat-Memory muss man die Größe der Stacks immer beschränken um eine vernünftige Koexistenz mehrerer Stack in einem virtuellen Adressraum sicherstellen zu können. Auch kann man bei Flat-Memory die Stack niemals 100% zuverlässig gegeneinander absichern wie ich da http://forum.lowlevel.eu/index.php?topic=2224.msg25456#msg25456 schon mal dargelegt hatte. Von daher bin ich in jedem Fall der Meinung das auch alle existierenden Programme von Segmentierung einen Nutzen haben können.

6.5.6 Additive Operators 9.
Danke, lese ich mir nachher mal durch.

&foo[i + 2] - &foo[i + 1] = (i + 2) - (i + 1) = 1
Also hier fehlt irgendwo noch "sizeof(TYPE)" weil der Abstand der Indizes ja nur 1 beträgt aber der Abstand der Pointer der Objekt-Größe entsprechen sollte.

(uintptr_t)&foo[i + 2] - (uintptr_t)&foo[i + 1] = sizeof(foo[0])
Also das ist IMHO auf jeden Fall falsch. Solange Du die Differenz aus zwei Pointern bildest muss auch eine Integer-Zahl (vom Type ptrdiff_t) bei raus kommen die auch wieder als Offset zu gebrauchen sein muss aber wenn Du beide Pointer vorher nach uintptr_t umwandelst dann ist das IMHO nicht mehr gewährleistet. Was ist wenn eine CPU mal tatsächlich eine andere Binärdarstellung für Adressen als für normale (Integer-)Zahlen benutzt? Dann würde Dein Code nicht mehr funktionieren, der C-Standard schreibt auch explizit nicht vor das für Integer das Zweierkomplement zu benutzen ist so das es jedem frei steht hier was anderes zu nutzen.

Ein Array ist kompakt.
Im Hinblick auf sizeof(Type) (also inklusive Padding) ja, da hast Du recht. Auch muss das Padding immer gleich sein, egal ob das Objekt in einem Array ist oder alleine benutzt wird oder Teil einer (größeren) Struktur ist. Wenn das nicht gewährleistet wäre könnte man solche Objekte ja nicht kopieren da dann eventuell mal zu viele oder zu wenige Bytes kopiert werden würden. Sowas wie "( (&TYPE[i+2]) - (&TYPE[i+1]) ) == sizeof(TYPE)" wird also doch immer true ergeben müssen, ebenso wie das ein (&TYPE)++ auch immer um sizeof(Type) Bytes vorrücken muss, da hab ich wohl gestern nicht zu Ende gedacht.

Aber das hier der Vergleich am Ende true ergibt ist IMHO nicht zugesichert :*TYPE p1,p2;
p1 = &type;
p2 = (*TYPE)(((uintptr_t)p1) + sizeof(TYPE));  // eines der Probleme hier ist das die Größe von uintptr_t und size_t (der Return-Type von sizeof) nicht identisch sein muss so dass das Ergebnis schon deswegen ungültig sein könnte
p1++;
if (p1 == p2)  // hier kommt nur dann true raus wenn für Pointer und für Integer die selbe Binärdarstellung in der CPU benutzt wird und das sichert der C-Standard nicht zu
So wie ich den C-Standard verstehe ist es nicht zugesichert das Rechenoperationen die direkt mit Pointern durchgeführt werden und Rechenoperationen die mit Integer-Werten von Pointern durchgeführt werden das selbe Ergebnis erzeugen. C-Code der auf sowas basiert ist IMHO nicht 100% konform und wenn der auf meiner Plattform nicht mehr funktioniert dann ist das ein Fehler im C-Code und nicht im Compiler. Deswegen möchte ich diese Dinge ja am liebsten gleich vom Compiler ablehnen lassen damit ich nicht später irgendwelchen Merkwürdigkeiten nachstellen muss, nebst dessen das ich für händische Pointer-Arithmetik (vor allem mit Integern) auch absolut keine Notwendigkeit sehe (sowas kann man immer auch anders machen, von ein paar Spezialfällen innerhalb der Speicherverwaltung mal abgesehen).


Grüße
Erik
59
Offtopic / Re: Eigene CPU
« am: 29. January 2012, 11:20 »
Hallo Sannaj,


ich hab noch mal etwas über Dein IR nachgedacht und mir sind da einige Probleme aufgefallen:
Wenn das Laden des IR und das Benutzen des IR mit unabhängigen Befehlen und in unterschiedlichen Pipeline-Stufen durchgeführt wird dann sehe ich ein Problem mit bedingten Sprüngen. Wenn nach so einem bedingtem Sprung ein IR-Lade-OpCode kommt und vom Decoder auch verarbeitet wird noch bevor für den bedingten Sprung feststeht ob dieser ausgeführt werden soll könnte es passieren dass das IR bereits mit einem neuen Wert geladen wird aber der Sprung trotzdem ausgeführt wird so das dann Befehle am Sprungziel im IR nicht den Wert vorfinden der als letztes vor dem bedingten Sprung geladen wurde sondern eventuell einen Wert der nach dem bedingtem Sprung geladen wurde. Ob das so passiert hängt von vielen Faktoren ab: vom Abstand (die Pipeline kann ja nur maximal eine gewisse Menge an Befehlen enthalten) aber auch davon ob der Speicher/Cache die nächsten Befehle schon an den Decoder geliefert hat. Damit würde die Situation entstehen das manche Befehle im OpCode-Stream die hinter dem bedingten Sprung kommen trotzdem ausgeführt werden und manche nicht und das auch noch ohne das der Compiler das immer eineindeutig ermitteln kann (eben weil das sicher auch von Umständen abhängt die erst zur Laufzeit bekannt sind und eventuell auch jedes mal anders ausfallen).
Ein weiteres Problem sind Exceptions und Interrupts. Du musst in der Lage sein das IR im Exception-Handler gezielt zu sichern und es am Ende des Exception-Handlers auch wieder herzustellen, ansonsten kannst Du nicht an beliebigen Stellen Exceptions/Interrupts zulassen.
In dieser Hinsicht gefällt mir das Konzept eines einfachen Load-Immediate-in-beliebiges-Register-Befehl am besten, entweder dieser Befehl wird in der Pipeline ausgeführt und ist damit für alle folgenden Befehle sichtbar oder er wird nicht ausgeführt und hat demzufolge auch keine sichtbaren Auswirkungen. Ich gebe zu das Dein IR durchaus seinen Reiz hat weil man damit mit jedem Befehl und für jeden Zweck ein Immediate benutzen kann aber wenn Du dafür eh ein Register opfern möchtest (also eine Register-Nummer) dann implementiere das als richtiges Register und mach einen Load-Immediate-Befehl der immer in dieses Register lädt und ganz normal von der Pipeline ausgeführt wird.

Nur 28 Bit für den eigentlichen Befehl würde ich persönlich als zu wenig betrachten, schau Dir mal an wie gedrängt es im klassischen ARM-Mode zugeht und dort wird die Bedingung (in den oberen 4 Bit) auch noch mitbenutzt um Befehle zu codieren. ARM hat auch nur 16 Register und das ist aus heutiger Sicht schon recht knapp bemessen.


Auf Micro-Code würde ich ganz verzichten, in einer RISC-CPU gibt es dafür IMHO keine Notwendigkeit. Ich glaube auch das Deine CPU dann die erste RISC-CPU wäre die Micro-Code benutzt und wie Du damit ein "BIOS" realisieren möchtest bzw. was Du damit meinst musst Du mal etwas genauer erläutern.


Grüße
Erik
60
Hallo,


Wiederholt durch 16 teilen und jeweils den Rest auf den Bildschirm ausgeben? ;)
Etwas das von printf mit %p erledigt wird und da die libc ja auch zur Plattform passen muss ist es IMHO kein Problem da drin auch mal einen kleinen Trick zu benutzen der nicht so ganz sauber ist (in meiner Heap-Implementierung baue ich auch Pointer recht frei zusammen und wieder auseinander, ich sehe da auch kein Problem darin das mein Code nicht portabel ist).

Nicht, dass ich wüsste (ich habe aber auch keine explizite Aussage gefunden, dass es undefiniert ist, der Standard scheint einfach nichts dazu zu sagen).
Also ich persönlich halte mich da lieber an die Devise: "alles was nicht ausdrücklich und explizit zugesichert wird ist auch nicht zugesichert, fertig".

Wenn du daraus also einen Segfault machen willst, ist das vermutlich erlaubt.
Ich denke auch dass das so erlaubt ist aber dafür würde ich immer zusätzlichen Code benötigen und das möchte ich auch wieder nicht, daher möchte ich das lieber gleich ganz verbieten um so den geringsten Aufwand zu haben.

Was ist daran schwierig? Unterschiedliche Segmente -> Segfault. Gleiche Segmente -> Differenz der Offsets wird berechnet.
Vielleicht mache ich mir das einfach auch nur zu schwierig. Eines meiner Probleme ist das wenn eine solche Differenz später wieder zu einem Pointer dazu addiert wird das es dann zu einem Überlauf kommen kann und der wird, falls er direkt im Speicherzugriffsbefehl passiert, von der CPU mit einer Exception beantwortet, es kann also passieren das die Funktionsfähigkeit des selben C-Codes vom Optimierungsgrad des Compilers abhängt und das sollte IMHO lieber vermieden werden.

Abgesehen davon, dass ich keine andere Methode kenne, die Offsets zu berechnen
offsetof(), das ist IMHO auch deswegen nötig weil ja das tatsächliche Speicherlayout in Strukturen auch wieder implementierungsspezifisch ist. Das meistens dahinter im Endeffekt nur der selbe Hack steckt den Du auch direkt benutzen würdest ist da erst mal egal, immerhin muss dafür derjenige gerade stehen der die libc für die konkrete Plattform gebaut hat und der sollte genau wissen was geht und was nicht.

"Fast C" heißt "nicht C", das ist eine neue Sprache, für die du erstmal eine ordentliche Spec schreiben solltest.
Das ist mir schon klar, aber eine komplette Spec werde ich da trotzdem nicht schreiben sondern eher eine präzise Auflistung der Unterschiede. Auf der anderen Seite scheint der C-Standard genügend "Interpretationsspielraum" zu bieten das ich wohl trotzdem sagen kann das mein System 100% konform ist, aber da kommen wir dann in Bereiche die sonst eher bei der Interpretation von Bibel, Koran usw. benutzt werden.

Pointerarithmetik ist genau definiert, solange du innerhalb von einem Objekt (oder einem Element nach Arrayende) bleibst.
Sicher? Das würde ich arg bezweifeln aber ich lese (morgen) am besten noch mal genau nach. Ich kann mich jedenfalls nicht erinnern das im C-Standard sowas wie "( (&TYPE[i+2]) - (&TYPE[i+1]) ) == sizeof(TYPE)" als true zugesichert wird. Um wie viel ein Pointer bei (&TYPE)++ wirklich inkrementiert wird ist wimre auch implementierungsspezifisch und muss ebenfalls nicht zwangsläufig mit sizeof(TYPE) übereinstimmen.

Wie groß dein Array war, musst du natürlich immer noch selber wissen. ;)
Ja klar, aber was ist mit Padding und ähnlichen Dingen? Sowas darf der Compiler frei nach Befinden oder gewünschtem Optimierungsgrad entscheiden. Arrays sind nicht zwangsläufig kompakt, wimre noch nicht einmal char-Arrays.

Aber wenn du ein char a[42] hast und p = &a[12], q = &a[14], dann ist genau definiert, dass  p + 2 * (q - p) = &a[16] ist, zum Beispiel.
Hm, okay, trotzdem würde ich das nicht als guten C-Code bezeichnen, in einem Array sollte man IMHO nur mit dem Index zugreifen und nicht mit Pointer-Arithmetik.

In der Praxis ist das genau dasselbe wie mit einem Integer herumzurechnen. Der theoretische Unterschied ist, dass es mit char* definiert und mit uintptr_t implementation defined.
Sicher? So wie ich den C-Standard verstanden habe wird kein exakter und eineindeutiger Zusammenhang zwischen Pointern für Objekte und deren numerische Darstellung als Integer zugesichert. Theoretisch könnte eine CPU ja auch Speicheradressen in Gray-Code darstellen (bei einem Pointer++ müsste der Compiler dann einen anderen Rechenbefehl benutzen als für Integer++) und echter Standard-konformer C-Code müsste trotzdem funktionieren. Das die Differenz von 2 Pointern als Integer den numerischen Wert 12 hat bedeutet nicht das die 2 Objekte (auf die die beiden Pointer zeigen) auch wirklich 12 Bytes von einander entfernt im Speicher liegen, dass das trotzdem auf allen heute existierenden CPUs zutrifft ist noch keine Zusicherung.


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

Einloggen