Ausgabe 7 — Änderungen 1817 → 1818

Zeile 34: Zeile 34:
 
und wünsche nun viel Verknügen.
 
und wünsche nun viel Verknügen.
  
−
===2. Überblick===
+
===Überblick===
 
Bei Multitasking gibt es 2 wichtige Teile, die man immer braucht. Der erste Teil ist eine
 
Bei Multitasking gibt es 2 wichtige Teile, die man immer braucht. Der erste Teil ist eine
 
Tabelle, in der alle Tasks aufgelistet sind. Im zweiten Teil wird der aktuelle Taskzustand
 
Tabelle, in der alle Tasks aufgelistet sind. Im zweiten Teil wird der aktuelle Taskzustand
Zeile 84: Zeile 84:
 
Aufbau:
 
Aufbau:
  
−
<table class="ntable" border="1" bordercolor="#000000" cellspacing="0" cellpadding="2"><tr><td class="tableinfo"><img src="http://www.joachim-neu.de/public/lowlevel/7/3_1.png" alt="TSS-Aufbau"><br></td></tr></table><br><p style="text-align:justify">
+
http://www.joachim-neu.de/public/lowlevel/7/3_1.png
 +
 
 
So. Nun werde ich den Aufbau genauer Erklären. Die <span style="background: #FFFF00">gelb</span> hinterlegten Einträge
 
So. Nun werde ich den Aufbau genauer Erklären. Die <span style="background: #FFFF00">gelb</span> hinterlegten Einträge
 
beizeichnen das Offset des Eintrags zum Beginn der Tabelle. Alle <span style="background: #FF0000">rot</span> hinterlegten
 
beizeichnen das Offset des Eintrags zum Beginn der Tabelle. Alle <span style="background: #FF0000">rot</span> hinterlegten
−
Einträge haben den Wert „0“ und sollten den auch beinhalten. Alle <span style="background: #0000FF">blau</span> hinterlegten
+
Einträge haben den Wert 0 und sollten den auch beinhalten. Alle <span style="background: #0000FF">blau</span> hinterlegten
 
Einträge bezeichnen vom Programm beeinflussbare Einträge. Alle <span style="background: #800080">lila</span> hinterlegten
 
Einträge bezeichnen vom Programm beeinflussbare Einträge. Alle <span style="background: #800080">lila</span> hinterlegten
 
Einträge müssen vom Betriebssystem gesetzt werden und sind nicht vom Programm
 
Einträge müssen vom Betriebssystem gesetzt werden und sind nicht vom Programm
Zeile 151: Zeile 152:
 
Auch in dieser Tabelle ist eine Zeile ein Word.
 
Auch in dieser Tabelle ist eine Zeile ein Word.
  
−
<img src="http://www.joachim-neu.de/public/lowlevel/7/3_3.png" alt="Task-Tabelle">
+
http://www.joachim-neu.de/public/lowlevel/7/3_3.png
  
 
Es gibt 2 Möglichkeiten, das Ende dieser Tabelle aus Task-Tabellen-Einträgen zu
 
Es gibt 2 Möglichkeiten, das Ende dieser Tabelle aus Task-Tabellen-Einträgen zu
 
finden.
 
finden.
−
1. Man speichert in einer Variable, wie viele Einträge man hat und überprüft das
+
# Man speichert in einer Variable, wie viele Einträge man hat und überprüft das aktuelle und das maximale Offset, um einen WrapArround (beim Anfang anfangen) zu vollziehen.
−
aktuelle und das maximale Offset, um einen WrapArround (beim Anfang anfangen)
+
# Man gibt am Ende der Tabelle dem nächsten leeren Eintrag die ID 0xFFFF oder ein sonstiges "Endezeichen" und führt einen WrapAround aus, sobald man als ID den Wert des Endezeichens gefunden hat.
−
zu vollziehen.
 
−
2. Man gibt am Ende der Tabelle dem nächsten leeren Eintrag die ID 0xFFFF oder ein
 
−
sonstiges "Endezeichen" und führt einen WrapAround aus, sobald man als ID den
 
−
Wert des Endezeichens gefunden hat.
 
  
−
Das war eigendlich schon das Wichtigste über die Task-Tabelle.
+
Das war eigentlich schon das Wichtigste über die Task-Tabelle.
  
 
===TaskGates===
 
===TaskGates===
Zeile 171: Zeile 168:
 
(wieder ist jede Zeile ein Word)
 
(wieder ist jede Zeile ein Word)
  
−
<img src="http://www.joachim-neu.de/public/lowlevel/7/3_4.png" alt="Taskgate">
+
http://www.joachim-neu.de/public/lowlevel/7/3_4.png
  
 
Alle Bereiche, die ''<span style="background: #FF0000">Reserviert</span>'' sind, sollten den Wert 0 beinhalten. Im Bereich ''<span style="background: #FFFF00">TSS-Deskriptor-Nummer</span>'' wird der Deskriptor festgehalten, auf den das TaskGate verweist.
 
Alle Bereiche, die ''<span style="background: #FF0000">Reserviert</span>'' sind, sollten den Wert 0 beinhalten. Im Bereich ''<span style="background: #FFFF00">TSS-Deskriptor-Nummer</span>'' wird der Deskriptor festgehalten, auf den das TaskGate verweist.
Zeile 217: Zeile 214:
 
folgende Anforderungen gestellt:
 
folgende Anforderungen gestellt:
  
−
1. Sie muss fair sein, was heißt, dass alle Tasks von Grund auf gleich zu behandeln
+
# Sie muss fair sein, was heißt, dass alle Tasks von Grund auf gleich zu behandeln sind, sodass kein Task ständig dran kommt und kein Task nie dran kommt.
−
sind, sodass kein Task ständig dran kommt und kein Task nie dran kommt.
+
# Sie darf nicht zu komplex sein, sodass siche die CPU mehr mit dieser als mit den Tasks beschäftigen würde.
−
2. Sie darf nicht zu komplex sein, sodass siche die CPU mehr mit dieser als mit den
+
# Sie muss unabhängig sein, das heißt, sie darf nicht mit der Anzahl der Tasks zusammenhängen, zum Beispiel nur bei 5 laufenden Tasks funktionieren.
−
Tasks beschäftigen würde.
+
# Sie sollte berechenbar sein, also nicht auf Zufallswerten basieren oder auf jedem System anderst funktionieren.
−
3. Sie muss unabhängig sein, das heißt, sie darf nicht mit der Anzahl der Tasks
+
# Sie darf nicht beeinflussbar oder manipulierbar sein.
−
zusammenhängen, zum Beispiel nur bei 5 laufenden Tasks funktionieren.
 
−
4. Sie sollte berechenbar sein, also nicht auf Zufallswerten basieren oder auf jedem
 
−
System anderst funktionieren.
 
−
5. Sie darf nicht beeinflussbar oder manipulierbar sein.
 
  
 
Es gibt viele verschiedene Strategien. Die einen benutzen Prioritätsstufen zum Einteilen
 
Es gibt viele verschiedene Strategien. Die einen benutzen Prioritätsstufen zum Einteilen
Zeile 234: Zeile 227:
 
und damit anderen den Vortritt lässt, wenn er gerade keine Rechenzeit benötigt. Sehr
 
und damit anderen den Vortritt lässt, wenn er gerade keine Rechenzeit benötigt. Sehr
 
häufige Scheduling Strategien sind ''Round Robin'', ''First Task First'' und ''Shortest
 
häufige Scheduling Strategien sind ''Round Robin'', ''First Task First'' und ''Shortest
−
Time Left''. Diese und einige andere werde ich nun ein bisschen erleutern:
+
Time Left''. Diese und einige andere werde ich nun ein bisschen erläutern:
  
−
====Round Robin===
+
===Round Robin===
 
Bei Round Robin werden alle Tasks in einer Kette hintereinander abgearbeitet und
 
Bei Round Robin werden alle Tasks in einer Kette hintereinander abgearbeitet und
 
jeder bekommt die gleiche Rechenzeit. Wenn man Prioritäten benutzt, so hat man
 
jeder bekommt die gleiche Rechenzeit. Wenn man Prioritäten benutzt, so hat man
Zeile 280: Zeile 273:
 
mehrere Möglichkeiten:
 
mehrere Möglichkeiten:
  
−
1. Ein Far-Jump oder Far-Call bei dem als Selektor ein TSS angegeben wird. Der
+
# Ein Far-Jump oder Far-Call bei dem als Selektor ein TSS angegeben wird. Der Offsetteil wird hierbei ignoriert.
−
Offsetteil wird hierbei ignoriert.
+
# Ein IRET nachdem ein Task durch ein TaskGate in der IDT aufgerufen wird, also das NT-Flag gesetzt ist.
−
2. Ein IRET nachdem ein Task durch ein TaskGate in der IDT aufgerufen wird, also das
+
# Ein Far-Jump oder Far-Call auf ein Task-Gate. Auch hier wird der Offsetteil ignoriert.
−
NT-Flag gesetzt ist.
 
−
3. Ein Far-Jump oder Far-Call auf ein Task-Gate. Auch hier wird der Offsetteil
 
−
ignoriert.
 
  
 
Es gibt also 2 Möglichkeiten:
 
Es gibt also 2 Möglichkeiten:
Zeile 469: Zeile 459:
 
zum Programmieren allgemein.
 
zum Programmieren allgemein.
  
−
1. Programmiere auf Sicherheit! Es geht nicht um einen Geschwindigkeitsrekord,
+
# Programmiere auf Sicherheit! Es geht nicht um einen Geschwindigkeitsrekord, sondern um ein stabiles Betriebssystem. Deswegen beachte und bedenke jeden Fehler, der auftreten könnte und richte Fehlerbehandlungen ein. Du musst sie nicht gleich rein Implementieren, aber schaffe (wenn auch nur leere) Funktionen dafür, die
−
sondern um ein stabiles Betriebssystem. Deswegen beachte und bedenke jeden
+
du später erweitern kannst. Somit hast du ein sicheres Gerüst und gerätst nicht in die Falle, dass ein Code nicht geht, weil ein unerwarteter Fehler aufgetreten ist.
−
Fehler, der auftreten könnte und richte Fehlerbehandlungen ein. Du musst sie nicht
+
# Schreibe nicht alles ab! Code den Code selber. Es wird dir helfen, das Zeug zu verstehen und eigener Code lässt sich besser ins System integrieren.
−
gleich rein Implementieren, aber schaffe (wenn auch nur leere) Funktionen dafür, die
+
# Entscheide dich fest für ein System und mach keine Abstriche. Versuche deine Gedanken durchzusetzen und gib nicht auf, bloß, weil was nicht klappt.
−
du später erweitern kannst. Somit hast du ein sicheres Gerüst und gerätst nicht in die
+
# Achte auch die Optimierung deines Codes. Schon kleine Teile könnte vieles verschnellern und dein System sollte das Minimum an Leistung verbrauchen.
−
Falle, dass ein Code nicht geht, weil ein unerwarteter Fehler aufgetreten ist.<br>
+
# Halte alles Modular, sprich baue auch für deinen Scheduler eine Funktion. Das wird es später erleichtern, die Funktion auszutauschen, wenn du eine andere Strategie verwenden willst.
−
2. Schreibe nicht alles ab! Code den Code selber. Es wird dir helfen, das Zeug zu
+
# Und als letztes: Kommentiere deinen Code gut. Gerade in Assembler ist das sehr wichtig.
−
verstehen und eigener Code lässt sich besser ins System integrieren.<br>
 
−
3. Entscheide dich fest für ein System und mach keine Abstriche. Versuche deine
 
−
Gedanken durchzusetzen und gib' nicht auf, blos, weil was nicht klappt.<br>
 
−
4. Achte auch die Optimierung deines Codes. Schon kleine Teile könnte vieles
 
−
verschnellern und dein System sollte das Minimum an Leistung verbrauchen.<br>
 
−
5. Halte alles Modular, sprich baue auch für deinen Scheduler eine Funktion. Das wird
 
−
es später erleichtern, die Funktion auszutauschen, wenn du eine andere Strategie
 
−
verwenden willst.
 
−
6. Und als letztes: Kommentiere deinen Code gut. Gerade in Assembler ist das sehr
 
−
wichtig.
 
  
 
Tja, das waren auch schon meine Tipps.
 
Tja, das waren auch schon meine Tipps.
Zeile 496: Zeile 476:
 
ermuntern, sich bei mir zu melden. Ich helfe, so gut ich kann. Meine Kontaktdaten gibt es im Impressum.</p>
 
ermuntern, sich bei mir zu melden. Ich helfe, so gut ich kann. Meine Kontaktdaten gibt es im Impressum.</p>
  
−
<h2><a name="Designtechnisches"></a>Designtechnisches</h2><p style="text-align:justify">
+
==Designtechnisches: Multitasking==
−
<p class="secthead">Multitasking</p>
+
 
 +
===Einleitung===
  
−
<br><b>0.Inhaltsangabe</b><br>
 
−
0.Inhaltsangabe
 
−
1.Einleitung
 
−
2.Grundlagen
 
−
3.Softwaretasking
 
−
4.Hardwaretasking
 
−
5.Schluss
 
−
<br><b>1.Einleitung</b><br>
 
 
Dies ist eine Abwägung zwischen zwe Designideen. Ich will die beiden verschiedenen Möglichkeiten von Multitasking  
 
Dies ist eine Abwägung zwischen zwe Designideen. Ich will die beiden verschiedenen Möglichkeiten von Multitasking  
−
(hardwarebasierendes und softwarebasierendes) miteinander abwiegen. Dieser Text soll keine Antwort auf die Frage geben,  
+
(hardwarebasierendes und softwarebasierendes) miteinander abwiegen. Dieser Text soll keine Antwort auf die Frage geben, welches Multitasking besser oder schlechter sei, sondern lediglich die verschiedenen Vor- und Nachteile aufzeigen und abwiegen.
−
welches Multitasking besser oder schlechter sei, sondern lediglich die verschiedenen Vor- und Nachteile aufzeigen und  
+
 
−
abwiegen.
+
===Grundlagen===
−
<br><b>2.Grundlagen</b><br>
+
Was ist Multitasking? Dieser Text soll sich zwar darum nicht kümmern, trotzdem werde ich die grundlegendsten Grundlagen aufzeigen. Multitasking ist die Fähigkeit eines Betriebssystems, mehrere Programme, sogenannte Tasks gleichzeitig/parallel laufen zu lassen. Dies ist auf einem mehrprozessorigen System leicht zu verstehen, jeder Prozessor bekommt einen Task zugewiesen, was aber, wenn nur ein Prozessor vorhanden ist? Dann muss man diesen unter den verschiedenen Tasks aufteilen, de gerade bereit sind, ausgeführt zu werden. Man muss also den aktuellen Prozessorzustand speichern und den des nächsten  
−
Was ist Multitasking? Dieser Text soll sich zwar darum nicht kümmern, trotzdem werde ich die grundlegendsten Grundlagen  
 
−
aufzeigen. Multitasking ist die Fähigkeit eines Betriebssystems, mehrere Programme, sogenannte Tasks gleichzeitig/parallel  
 
−
laufen zu lassen. Dies ist auf einem mehrprozessorigen System leicht zu verstehen, jeder Prozessor bekommt einen Task  
 
−
zugewiesen, was aber, wenn nur ein Prozessor vorhanden ist? Dann muss man diesen unter den verschiedenen Tasks aufteilen,  
 
−
de gerade bereit sind, ausgeführt zu werden. Man muss also den aktuellen Prozessorzustand speichern und den des nächsten  
 
 
Tasks laden. Wichtig dabei ist, dass alle Werte gespeichert werden, die einen Task beschreiben, also Registerinhalte,  
 
Tasks laden. Wichtig dabei ist, dass alle Werte gespeichert werden, die einen Task beschreiben, also Registerinhalte,  
 
Flags, aktuelle Position im Code und so weiter. Der Task an sich darf davon nix merken, er darf nicht bemerken, dass er  
 
Flags, aktuelle Position im Code und so weiter. Der Task an sich darf davon nix merken, er darf nicht bemerken, dass er  
−
unterbrochen wurde oder, dass etwaige Register nicht die selben Werte wie vorher haben.<br>
+
unterbrochen wurde oder, dass etwaige Register nicht die selben Werte wie vorher haben.
−
Es gibt zwei Verschiedene Methoden, Multitasking durchzuführen, kooperativ oder preemptiv. Kooperatives Multitasking besagt,  
+
 
 +
Es gibt zwei verschiedene Methoden, Multitasking durchzuführen, kooperativ oder preemptiv. Kooperatives Multitasking besagt,  
 
dass das Programm die Kontrolle über den PC von alleine wieder an das Betriebssystem zurück gibt, welches diese dann neu  
 
dass das Programm die Kontrolle über den PC von alleine wieder an das Betriebssystem zurück gibt, welches diese dann neu  
 
verteilt, preemptives Multitasking besagt, dass dem Task die Kontrolle in bestimmten Zeitabständen vom System entzogen und  
 
verteilt, preemptives Multitasking besagt, dass dem Task die Kontrolle in bestimmten Zeitabständen vom System entzogen und  
Zeile 530: Zeile 499:
 
das System umbiegen kann, und somit in regelmäßigen Abständen die Kontrolle über das System zurück erlangt. <br>
 
das System umbiegen kann, und somit in regelmäßigen Abständen die Kontrolle über das System zurück erlangt. <br>
 
Es gibt auch Mischformen zwischen preemptivem und kooperativem Multitasking, in welchen das System darauf setzt, dass das  
 
Es gibt auch Mischformen zwischen preemptivem und kooperativem Multitasking, in welchen das System darauf setzt, dass das  
−
Programm die Kontrolle von alleine abgibt, dies aber über den Timer überwacht und notfalls einschreitet.<br>
+
Programm die Kontrolle von alleine abgibt, dies aber über den Timer überwacht und notfalls einschreitet.
 +
 
 
Ein Multitaskingsystem benötigt immer einen Interrupt, das die Kontrolle entzieht, einen Dispatcher, der den Status  
 
Ein Multitaskingsystem benötigt immer einen Interrupt, das die Kontrolle entzieht, einen Dispatcher, der den Status  
−
speichert und beim neuen wieder läd und einen Scheduler, der den Task auswählt, der als nächstes zu starten ist. Der  
+
speichert und beim neuen wieder läd und einen Scheduler, der den Task auswählt, der als nächstes zu starten ist. Der Scheduler wählt diesen Task anhand der Scheduling Strategie aus.
−
Scheduler wählt diesen Task anhand der Scheduling Strategie aus.<br>
+
 
 
Die Unterschiede zwischen Softwaretasking und Hardwaretasking liegen lediglich im Dispatcher.
 
Die Unterschiede zwischen Softwaretasking und Hardwaretasking liegen lediglich im Dispatcher.
  
−
<br><b>3.Softwaretasking</b><br>
+
===Softwaretasking===
 
So, nun an die echte Arbeit. Softwaretasking. Beim softwarebasierenden Tasking setzt der Dispatcher darauf, den aktuellen  
 
So, nun an die echte Arbeit. Softwaretasking. Beim softwarebasierenden Tasking setzt der Dispatcher darauf, den aktuellen  
 
Taskstatus auf dem taskeigenen Stack, dem Stapelspeicher zu speichern und später wieder von diesem zu laden. Verfechter  
 
Taskstatus auf dem taskeigenen Stack, dem Stapelspeicher zu speichern und später wieder von diesem zu laden. Verfechter  
Zeile 550: Zeile 520:
 
einfaches System, mit dem man schnell die Grundlagen von Multitasking erfüllen kann. Kompliziert wird es allerdings, wenn  
 
einfaches System, mit dem man schnell die Grundlagen von Multitasking erfüllen kann. Kompliziert wird es allerdings, wenn  
 
man das Konzept ausbauen und verfeinern will. Außerdem kommt man nie ganz um TSS rum, auch bei Softwaretasking braucht man  
 
man das Konzept ausbauen und verfeinern will. Außerdem kommt man nie ganz um TSS rum, auch bei Softwaretasking braucht man  
−
mindestens ein TaskStateSegment.<br>
+
mindestens ein TaskStateSegment.
 +
 
 
Auch stehen viele Funktionen des Protected Mode erst mit TSS richtig zur Verfügung, man denke an das explizite Sperren von  
 
Auch stehen viele Funktionen des Protected Mode erst mit TSS richtig zur Verfügung, man denke an das explizite Sperren von  
 
Ports zum Beispiel. Aber auch deshalb verbraucht das Softwaretasking relativ wenig Speicher. Die Stacks können ausgelagert  
 
Ports zum Beispiel. Aber auch deshalb verbraucht das Softwaretasking relativ wenig Speicher. Die Stacks können ausgelagert  
 
werden, sodass der Speicherverbrauch im RAM auf das Minimum reduziert wird und man kann auswählen, welche Informationen  
 
werden, sodass der Speicherverbrauch im RAM auf das Minimum reduziert wird und man kann auswählen, welche Informationen  
−
man speichern will, und welche nicht.<br>
+
man speichern will, und welche nicht.
−
</p><table class="ntable" border="1" bordercolor="#000000" cellspacing="0" cellpadding="2">
 
−
<tr><th class="infohead">+</th><th class="infohead">-</th></tr>
 
−
<tr><td class="tableinfo">
 
−
Hohe Geschwindigkeit beim Taskwechsel.<br>
 
−
Sehr einfach zu implementieren.<br>
 
−
Wenig Platzverbraucht.<br>
 
  
−
</td><td class="tableinfo">
+
{|
−
Verwirrend wegen TSS.<br>
+
| +
−
Schwer zu erweitern.<br>
+
| -
−
Nicht alle Möglichkeiten des Protected Mode benutzbar.<br>
+
|-
−
</td></tr>
+
|
−
</table><br><p style="text-align:justify">
+
* Hohe Geschwindigkeit beim Taskwechsel
−
<br><b>4.Hardwaretasking</b><br>
+
* Sehr einfach zu implementieren
 +
* Wenig Platzverbrauch
 +
|
 +
* Verwirrend wegen TSS
 +
* Schwer zu erweitern
 +
* Nicht alle Möglichkeiten des Protected Mode benutzbar
 +
|}
 +
 
 +
===Hardwaretasking===
 
Hardwaretasking. Wie der Name schon sagt setzt das hardwarebasierende Multitasking auf die Möglichkeiten der CPU zum  
 
Hardwaretasking. Wie der Name schon sagt setzt das hardwarebasierende Multitasking auf die Möglichkeiten der CPU zum  
 
Speichern des aktuellen Taskzustandes. Dazu gibt es ab jedem 286er ein sogenanntes TaskStateSegment, in welchem die  
 
Speichern des aktuellen Taskzustandes. Dazu gibt es ab jedem 286er ein sogenanntes TaskStateSegment, in welchem die  
Zeile 583: Zeile 556:
 
Auch ist alles das gleiche, man braucht also nicht wie bei Softwaretasking noch irgendein Segment oder ähnliches, wobei  
 
Auch ist alles das gleiche, man braucht also nicht wie bei Softwaretasking noch irgendein Segment oder ähnliches, wobei  
 
man aber mindestens zwei Tasks braucht, die gerade laufen, da man sonst nicht wechseln kann, weil TSS-Tasks nicht reentrant  
 
man aber mindestens zwei Tasks braucht, die gerade laufen, da man sonst nicht wechseln kann, weil TSS-Tasks nicht reentrant  
−
sind, sprich man einen aktiven Task nicht wieder aktivieren kann.<br>
+
sind, sprich man einen aktiven Task nicht wieder aktivieren kann.
−
</p><table class="ntable" border="1" bordercolor="#000000" cellspacing="0" cellpadding="2">
+
{|
−
<tr><th class="infohead">+</th><th class="infohead">-</th></tr>
+
| +
 +
| -
 +
|-
 +
|
 +
* Die CPU nimmt viele Aufgaben ab
 +
* Man kann alle Möglichkeiten des PM ausschöpfen
 +
* Lässt sich leicht erweitern
 +
|-
 +
* Verbraucht viel Platz
 +
* Taskwechsel dauert relativ lange
 +
* Komplizierter Taskwechsel mit Opcodes
 +
|}
  
−
<tr><td class="tableinfo">
+
===Schluss===
−
Die CPU nimmt viele Aufgaben ab.<br>
 
−
Man kann alle Möglichkeiten des PM ausschöpfen.<br>
 
−
Lässt sich leicht erweitern.<br>
 
−
</td><td class="tableinfo">
 
−
Verbraucht viel Platz.<br>
 
−
Taskwechsel dauert relativ lange.<br>
 
−
Komplizierter Taskwechsel mit Opcodes.<br>
 
−
</td></tr>
 
−
</table><br><p style="text-align:justify">
 
−
<br><b>5.Schluss</b><br>
 
  
 
So, ich hoffe, ich hab mit dem Text hier einigen die Entscheidung zwischen Software- und Hardwaretasking erleichtert.
 
So, ich hoffe, ich hab mit dem Text hier einigen die Entscheidung zwischen Software- und Hardwaretasking erleichtert.
 
Letztendlich liegt es nur am Programmierer selber, was er am liebsten mag. Bei Fragen bin ich auch wieder durch meine
 
Letztendlich liegt es nur am Programmierer selber, was er am liebsten mag. Bei Fragen bin ich auch wieder durch meine
−
Kontaktdaten im Impressum erreichbar.</p>
+
Kontaktdaten im Impressum erreichbar.
  
−
<h2><a name="Architekturtechnisches"></a>Architekturtechnisches</h2><p style="text-align:justify">
+
==Architekturtechnisches: Datenveränderungen im RAM==
−
<p class="secthead">Datenveränderungen im RAM</p>
+
===Einleitung===
−
<b>I.Einleitung</b><br>
 
 
Ich schreibe dieses Tutorial für Leute, die wie ich anfangs das Prinzip des Speicherns von Daten im RAM nicht verstehen.  
 
Ich schreibe dieses Tutorial für Leute, die wie ich anfangs das Prinzip des Speicherns von Daten im RAM nicht verstehen.  
 
Dabei geht es nicht um Programmiersprachenbefehle, sondern viel mehr darum, was mit den Daten im RAM gemacht wird.
 
Dabei geht es nicht um Programmiersprachenbefehle, sondern viel mehr darum, was mit den Daten im RAM gemacht wird.
−
  Dieses „Phänomen“ kann man besonderst gut sehen, wenn man mal das DWORD 0x12345678 byteweise ausließt. Man erhält  
+
  Dieses "Phänomen" kann man besonders gut sehen, wenn man mal das DWORD 0x12345678 byteweise ausließt. Man erhält  
−
das hier: 0x78,0x56,0x34 und 0x12. Man stellt sich nun die Frage, warum dies so ist. Nun, vielleicht sind Ihnen  
+
das hier: 0x78,0x56,0x34 und 0x12. Man stellt sich nun die Frage, warum dies so ist. Nun, vielleicht sind Ihnen
−
BigEndian und LittleEndian ein Begriff. Falls nicht, werde ich dies erstmal erklären.<br>
+
BigEndian und LittleEndian ein Begriff. Falls nicht, werde ich dies erstmal erklären.
−
<b>II.BigEndian</b><br>
+
 
 +
===BigEndian / LittleEndian===
 
BigEndian ist eine Form, eine Zahl zu speichern. Bei dieser Form speichert man das wichtigste Bit (also das, das bei  
 
BigEndian ist eine Form, eine Zahl zu speichern. Bei dieser Form speichert man das wichtigste Bit (also das, das bei  
 
einer Veränderung die Zahl am meisten beeinflussen würde) an erster Stelle und danach die anderen, also das zweitwichtigste  
 
einer Veränderung die Zahl am meisten beeinflussen würde) an erster Stelle und danach die anderen, also das zweitwichtigste  
 
und so weiter. Dies ist das System, nach welchem auch wir unsere Zahlen darstellen. Die höchstwertigste Stelle als erstes.
 
und so weiter. Dies ist das System, nach welchem auch wir unsere Zahlen darstellen. Die höchstwertigste Stelle als erstes.
−
<br>
 
−
<b>III.LittleEndian</b><br>
 
  
 
LittleEndian ist das genaue Gegenteil von BigEndian. Es beginnt mit dem „last significant“ Bit, also dem unwichtigsten  
 
LittleEndian ist das genaue Gegenteil von BigEndian. Es beginnt mit dem „last significant“ Bit, also dem unwichtigsten  
−
im Gegensatz zu dem „most significant“ Bit bei BigEndian. Das System von LittleEndian wird in der normalen Zahlenwelt  
+
im Gegensatz zu dem ''most significant'' Bit bei BigEndian. Das System von LittleEndian wird in der normalen Zahlenwelt  
 
der Menschen nicht benutzt. Jedoch benutzt es der Computer, da diese Art von Datenspeicherung ermöglicht, dass der  
 
der Menschen nicht benutzt. Jedoch benutzt es der Computer, da diese Art von Datenspeicherung ermöglicht, dass der  
 
Computer Zahlenwerte aus dem RAM lesen kann, ohne vorher deren Anzahl von Stellen zu kennen. Bei LittleEndian muss  
 
Computer Zahlenwerte aus dem RAM lesen kann, ohne vorher deren Anzahl von Stellen zu kennen. Bei LittleEndian muss  
 
der PC nur Bit für Bit lesen und die Zahl, welche er davor hat mit 2 multiplizieren, um dann das neue Bit zu addieren.  
 
der PC nur Bit für Bit lesen und die Zahl, welche er davor hat mit 2 multiplizieren, um dann das neue Bit zu addieren.  
 
Bei BigEndian müsste der Computer wissen, wie viele Stellen die Zahl hat, um dem 1. Bit mit dem passenden Stellenwert  
 
Bei BigEndian müsste der Computer wissen, wie viele Stellen die Zahl hat, um dem 1. Bit mit dem passenden Stellenwert  
−
zu multiplizieren.<br>
+
zu multiplizieren.
−
<b>IV.Auflösung</b><br>
+
 
 +
===Auflösung===
 
Da wir nun also geklärt haben, was Big- und LittleEndian sind und deren Aufbau, sowie deren Benutzung geklärt haben,  
 
Da wir nun also geklärt haben, was Big- und LittleEndian sind und deren Aufbau, sowie deren Benutzung geklärt haben,  
 
können wir mit einem Beispiel fortfahren. Gegeben ist eine Zahl von der Größe WORD, also 16 Bit. Diese sieht so aus:  
 
können wir mit einem Beispiel fortfahren. Gegeben ist eine Zahl von der Größe WORD, also 16 Bit. Diese sieht so aus:  
Zeile 631: Zeile 604:
 
0010110001001000. Dies ergibt in Hex 0x2C48. Da wir nun aber als kleinste Einheit Byts lesen können würden wir diese Bytes  
 
0010110001001000. Dies ergibt in Hex 0x2C48. Da wir nun aber als kleinste Einheit Byts lesen können würden wir diese Bytes  
 
erhalten: 0x34 und 0x12. Die beiden Bytes währen also vertauscht. Wenn man ein DWORD schreibt, und dies in Bytes ausließt,  
 
erhalten: 0x34 und 0x12. Die beiden Bytes währen also vertauscht. Wenn man ein DWORD schreibt, und dies in Bytes ausließt,  
−
erhält man zuerst das letzte, dann das vorletzte, dann das zweite und dann das erste Byte.<br>
+
erhält man zuerst das letzte, dann das vorletzte, dann das zweite und dann das erste Byte.
−
<b>V.Einsatz</b><br>
 
−
Wichtig ist diese Kenntniss, wenn wir Tabellen, die wir sehr oft aus Tutorials bekommen in anderen Datentypen belegen und
 
−
benutzen wollen, als vorgegeben. Wir müssen diese Phönomene erkennen und uns danach richten, damit wir immer die richtigen
 
−
Stellen in einem Speicherteil benutzen.<br>
 
−
<b>VI.Schluss</b><br>
 
−
So, das war auch schon alles, was ich dazu zu sagen hab. Ich hoffe, alles is klar geworden, falls nicht bin ich immer unter
 
−
meinen Kontaktdaten erreichbar. Diese stehen im Impressum.</p>
 
  
−
<h2><a name="Hardwaretechnisches"></a>Hardwaretechnisches</h2><p style="text-align:justify">
+
===Einsatz===
 +
Wichtig ist diese Kenntnis, wenn wir Tabellen, die wir sehr oft aus Tutorials bekommen in anderen Datentypen belegen und benutzen wollen, als vorgegeben. Wir müssen diese Phönomene erkennen und uns danach richten, damit wir immer die richtigen Stellen in einem Speicherteil benutzen.
  
−
<p class="secthead">Der PC-Lautsprecher</p>
+
===Schluss===
−
<b>1. Theorie:</b><br>
+
So, das war auch schon alles, was ich dazu zu sagen hab. Ich hoffe, alles is klar geworden, falls nicht bin ich immer unter meinen Kontaktdaten erreichbar. Diese stehen im Impressum.
 +
 
 +
==Hardwaretechnisches: Der PC-Lautsprecher==
 +
===Theorie===
 
Wir werden jetzt zuerst ein bisschen Theorie machen und uns danach mit der Praxis beschäftigen.
 
Wir werden jetzt zuerst ein bisschen Theorie machen und uns danach mit der Praxis beschäftigen.
 
Der PC Lautsprecher wird über den Timer-Baustein angesteuert, der als Zeitgeber und Zähler
 
Der PC Lautsprecher wird über den Timer-Baustein angesteuert, der als Zeitgeber und Zähler
Zeile 653: Zeile 623:
 
haben, weshalb im Code immer exakt geprüft werden sollte, ob die Port-Adressen stimmen.<br>
 
haben, weshalb im Code immer exakt geprüft werden sollte, ob die Port-Adressen stimmen.<br>
 
Jeder dieser 3 Kanäle besitzt ein Latch-Register und ein Counter-Register, die beide 16 Bit breit
 
Jeder dieser 3 Kanäle besitzt ein Latch-Register und ein Counter-Register, die beide 16 Bit breit
−
sind, zwei Signaleingänge (CLOCK und GATE) sowie einen Signalausgang (OUT).<br>
+
sind, zwei Signaleingänge (CLOCK und GATE) sowie einen Signalausgang (OUT).
 +
 
 
Jetzt zur Funktionsweise: Am Eingang CLOCK liegt eine konstante Frequenz von 1,19318 Mhz an.
 
Jetzt zur Funktionsweise: Am Eingang CLOCK liegt eine konstante Frequenz von 1,19318 Mhz an.
 
(Das heißt, dass vom Timer 1193180 mal pro Sekunde eins an den Eingang geschickt wird.) In das
 
(Das heißt, dass vom Timer 1193180 mal pro Sekunde eins an den Eingang geschickt wird.) In das
Zeile 660: Zeile 631:
 
das Counter-Register den Wert 0 erreicht, wird ein Puls über Ausgang OUT geschickt. Nacheinander
 
das Counter-Register den Wert 0 erreicht, wird ein Puls über Ausgang OUT geschickt. Nacheinander
 
entsteht so bei Wiederholung eine Frequenz von 1193180/Teiler, die beim Lautsprecher
 
entsteht so bei Wiederholung eine Frequenz von 1193180/Teiler, die beim Lautsprecher
−
ankommt, der das ganze dann in einen Ton umwandelt.<br>
+
ankommt, der das ganze dann in einen Ton umwandelt.
 +
 
 
Das Kommandoregister wird zum Seuern dieses Bausteins mit dem Kommandobyte geladen,
 
Das Kommandoregister wird zum Seuern dieses Bausteins mit dem Kommandobyte geladen,
−
welches z.B. einstellt, welche Betriebsart gewählt wurde. Das Kommandobyte ist so aufgebaut:<br>
+
welches z.B. einstellt, welche Betriebsart gewählt wurde. Das Kommandobyte ist so aufgebaut:
−
</p><table class="ntable" border="1" bordercolor="#000000" cellspacing="0" cellpadding="2"><tr><td class="tableinfo"><img src="http://www.joachim-neu.de/public/lowlevel/7/6_1.png" alt="Kommandobyte"><br></td></tr></table><br><p style="text-align:justify">
+
 
 +
http://www.joachim-neu.de/public/lowlevel/7/6_1.png
 +
 
 
Die Betriebsart bestimmt die Länge der Pulsfolge und, ob sie sich automatisch wiederholt usw. Der
 
Die Betriebsart bestimmt die Länge der Pulsfolge und, ob sie sich automatisch wiederholt usw. Der
 
Code 011 bestimmt, dass eine Pulsfolge erzeugt wird, die zum Erzeugen von Tönen nützlich ist.
 
Code 011 bestimmt, dass eine Pulsfolge erzeugt wird, die zum Erzeugen von Tönen nützlich ist.
Zeile 669: Zeile 643:
 
noch festgelegt, ob nur das High-Byte, nur das Low-Byte oder beide hintereinander (zuerst das
 
noch festgelegt, ob nur das High-Byte, nur das Low-Byte oder beide hintereinander (zuerst das
 
Low-Byte, dann das High-Byte) bearbeitet werden sollen. Das 0.Bit legt fest, ob die Zahl im
 
Low-Byte, dann das High-Byte) bearbeitet werden sollen. Das 0.Bit legt fest, ob die Zahl im
−
Kommandobyte binär- oder BCD-codiert lesen soll.<br>
+
Kommandobyte binär- oder BCD-codiert lesen soll.
−
Hier ein Beispiel:<br>
+
 
 +
Hier ein Beispiel: Das Kommandobyte 0xB6 = 10110110 stellt ein, dass...
 +
* der Timer-Kanal 2 programmiert werden soll,
 +
* erst das Low-und dann das High-Byte bearbeitet werden soll
 +
* eine symetrische Pulsfolge erzeugt werden soll,
 +
* das Kommandobyte binär zu interpretieren ist.
 +
 
 +
Die Programmierung des Timer-Bausteins erfolgt in 2 Schritten:
 +
# Kommandobyte in den Kommandoport schreiben, und dadurch die Anweisungen verteilen.
 +
# Teiler in den Port des augewählten Timer-Kanals schreiben.
  
−
Das Kommandobyte 0xB6 = 10110110 stellt ein, dass:<br>
 
−
– der Timer-Kanal 2 programmiert werden soll,<br>
 
−
– erst das Low-und dann das High-Byte bearbeitet werden soll<br>
 
−
– eine symetrische Pulsfolge erzeugt werden soll,<br>
 
−
– das Kommandobyte binär zu interpretieren ist.<br>
 
−
Die Programmierung des Timer-Bausteins erfolgt in 2 Schritten:<br>
 
−
1. Kommandobyte in den Kommandoport schreiben, und dadurch die Anweisungen verteilen.<br>
 
−
2. Teiler in den Port des augewählten Timer-Kanals schreiben.<br>
 
 
So jetzt könnten wir zwar Töne ausgeben, aber wir müssen dazu zuerst noch den Lautsprecher
 
So jetzt könnten wir zwar Töne ausgeben, aber wir müssen dazu zuerst noch den Lautsprecher
 
anstellen (und später wieder ausstellen). Das ist ganz schlau geregelt. Der Lautsprecher ist über ein
 
anstellen (und später wieder ausstellen). Das ist ganz schlau geregelt. Der Lautsprecher ist über ein
Zeile 689: Zeile 664:
 
wieder ausgeschaltet. Das ist eigendlich schon die gesamte Theorie, kommen wir jetzt zur Praxis!
 
wieder ausgeschaltet. Das ist eigendlich schon die gesamte Theorie, kommen wir jetzt zur Praxis!
  
−
<br><b>2. Praxis:</b><br>
+
===Praxis===
 
Wir werden jetzt ein paar Funktionen für die Programmiersprache C zusammen entwickeln.
 
Wir werden jetzt ein paar Funktionen für die Programmiersprache C zusammen entwickeln.
 
Nebenher schreiben wir die Funktionen dann auch noch in Assembler.
 
Nebenher schreiben wir die Funktionen dann auch noch in Assembler.
Zeile 696: Zeile 671:
 
Wir wissen, wir schalten den Lautsprecher an, indem die letzten 2 Bits in Port 0x61 auf 11b stehen.
 
Wir wissen, wir schalten den Lautsprecher an, indem die letzten 2 Bits in Port 0x61 auf 11b stehen.
 
Daraus machen wir schnell eine Funktion:
 
Daraus machen wir schnell eine Funktion:
−
</p><pre class="code"><div id="title"><br></div>
+
 
 +
<pre>
 
void switch_on()
 
void switch_on()
 
{
 
{
 
outp(0x61,inp(0x61) | 3);
 
outp(0x61,inp(0x61) | 3);
 
}
 
}
−
</pre><br><p style="text-align:justify">
+
</pre>
 +
 
 
Okay. In Assembler baue ich das schon alles mit in die _sound-Funktion ein.
 
Okay. In Assembler baue ich das schon alles mit in die _sound-Funktion ein.
 
So, an können wir ihn machen, nur aus noch nicht, aber wir wissen, wenn die beiden letzten Bits in
 
So, an können wir ihn machen, nur aus noch nicht, aber wir wissen, wenn die beiden letzten Bits in
 
Port 0x61 auf 00b stehen, dann ist der Lautsprecher aus. Das geht also ganz leicht:
 
Port 0x61 auf 00b stehen, dann ist der Lautsprecher aus. Das geht also ganz leicht:
−
</p><pre class="code"><div id="title"><br></div>
+
 
 +
<pre>
 
void switch_off()
 
void switch_off()
 
{
 
{
 
outp(0x61,inp(0x61) &~3);
 
outp(0x61,inp(0x61) &~3);
 
}
 
}
−
</pre><br><p style="text-align:justify">
+
</pre>
 +
 
 
Und in Assembler:
 
Und in Assembler:
−
</p><pre class="code"><div id="title"><br></div>
+
<pre>
 
_switch_off:
 
_switch_off:
 
IN AL,61h
 
IN AL,61h
Zeile 718: Zeile 697:
 
OUT 61h,AL
 
OUT 61h,AL
 
RET
 
RET
−
</pre><br><p style="text-align:justify">
+
</pre>
 +
 
 
Fertig. An und aus können wir ihn schon machen, aber das Herzstückt kommt noch! Einen Ton
 
Fertig. An und aus können wir ihn schon machen, aber das Herzstückt kommt noch! Einen Ton
 
ausgeben. Das geht mit folgendem, diesmal zuerst in Assembler ;-):
 
ausgeben. Das geht mit folgendem, diesmal zuerst in Assembler ;-):
−
</p><pre class="code"><div id="title"><br></div>
 
  
 +
<pre>
 
_sound:
 
_sound:
 
MOV AX,34DDH ;Die Frequenz wird in BX übergeben.
 
MOV AX,34DDH ;Die Frequenz wird in BX übergeben.
Zeile 744: Zeile 724:
 
DONE1:
 
DONE1:
 
RET
 
RET
−
</pre><br><p style="text-align:justify">
+
</pre>
 +
 
 
So, jetzt in C:
 
So, jetzt in C:
−
</p><pre class="code"><div id="title"><br></div>
+
<pre>
 
void sound(unsigned frequenz)
 
void sound(unsigned frequenz)
 
{
 
{
Zeile 758: Zeile 739:
 
//switch_off aufgerufen werden.
 
//switch_off aufgerufen werden.
 
}
 
}
−
</pre><br><p style="text-align:justify">
+
</pre>
−
<b>3. Schluss:</b><br>
+
 
 +
===Schluss===
 
So, geschafft! Das waren die Geheimnisse des PC-Lautsprechers! Zwei Sachen muss beim
 
So, geschafft! Das waren die Geheimnisse des PC-Lautsprechers! Zwei Sachen muss beim
 
Nachmachen noch beachtet werden: 1. Es muss zwischen den Tönen eine Funktion benutzt werden,
 
Nachmachen noch beachtet werden: 1. Es muss zwischen den Tönen eine Funktion benutzt werden,