Autor Thema: Verrückter als wir...?  (Gelesen 119733 mal)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #100 am: 17. December 2006, 21:49 »
Genau das, 4 Gatter war jetzt nur ein Beispiel von mir.
Dabei gilt die Angabe für die Gatterzahl immer hintereinander pro Signal, also wenn du 100 Gatter verbaust und dabei 5 Datenleitungen mit je 20 Gattern benutzt, sind das trotzdem nur 20 Gatter, die zählen :)
Ähm was meinst du mit Datenleitung??
Na halt ein Draht von Anfang bis Ende... :)

Zitat
Was das Pipelining betrifft, so halte ich es durchaus für möglich oder zweckmäßig, eine kleine Pipeline einzubinden. Zumindest schaffst du so eine relativ einfache Geschwindigkeitserhöhung. Aber du musst natürlich deinen Assembler auch entsprechend basteln - wenn du eine 3stufige Pipeline hast, müssen nach jedem Sprungbefehl 2 NOPs folgen; ebenso musst du bei aufeinanderfolgenden Registerzugriffen 2 NOPs abwarten (sonst ist der Wert u.U. noch nicht im jeweiligen Register angekommen).
OK, aber so ein NOP wäre ja dann auch ein eigenständiger Befehl?? Oder nich?

Klar. Aber der tut nichts böses, d.h. der pfuscht nicht in den Registern rum und auch nicht im Speicher. Wenn du einen JMP machst und du vergisst das, dann denke daran, dass du ja bereits zwei Opcodes geladen hast (3stufige Pipeline) - d.h. die beiden auf den JMP folgenden Opcodes sind (teilweise) schon ausgeführt - das darf nicht passieren, sonst zerstörst du dir den Programmablauf.

Zitat
In Betracht ziehen -musst- du es nicht, aber ich persönlich fände es praktisch. Zumal du dann drei voneinander unabhängige Einheiten produzierst, was sicherlich nicht die schlechteste Idee ist.
Hmm ja wie kann denn die ALU drei Befehle gleichzeitig ausführen? Dann bräuchte es ja 6 Eingangs + 3 Ausgangsregister??
Oder ist da nur gemeint die Befehlsverarbeitung vor der ALU 3stufig zu machen???
Das würde ja eingentlich heissen, dass alles 3x vorhanden sein muss...??

Ne, du hast das Prinzip des Pipelinings nicht begriffen... oder ich hab mich vermüllt ausgedrückt.

Du hast drei Teile:

(a) Opcode laden & decodieren
(b) Opcode ausführen
(c) Ergebnisse sichern, Register schreiben

Alle drei Teile können gleichzeitig arbeiten, um keine Rechenleistung zu verschwenden. Wenn jetzt jeder Schritt 1 CPU-Takt dauert, dann braucht auch jeder Befehl 3 Takte zum Ausführen (Decodieren, Ausführen, Sichern). Aber du schaffst es, pro Takt einen Befehl auszuführen - obwohl trotzdem alles 3 Takte dauert. Das ist Pipelining.
Aber dabei musst du eben beachten, dass du in der Pipeline Brüche haben kannst, die du nicht hardwareseitig bearbeiten willst (=> Aufwand); das musst du dann im Assembler berücksichtigen. "JMP" wird dann zu "JMP NOP NOP", weil du ja nicht weißt, was die beiden folgenden Opcodes tun.

Übrigens: (b) ist die ALU, (a) und (c) sind getrennte Teile. Ich meine keinen Multicore... :)

Gruß,
Svenska

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #101 am: 17. December 2006, 21:54 »
OK das Prinzip ist jetzt klar.

Aber der Punkt c ist ja eigenltich keiner, wenn die ALU ihre Endwerte direkt ins entsprechende Register schreibt.
Und b muss ja nicht immer die ALU sein, z.B. bei nem mov...

Wie wärs mit:
a)befehl laden + ip erhöhen
b)Überprüfung auf MOV, Bedingung(ist jetzt ein eigenständiger Befehl) oder NOP
c)Register auf ALU oder aufeinander legen bei (MOV/Bedingung)
d)Abarbeitung der Befehle

Dann wärs halt 4-stufig.


Gruss
Noooooooooos
« Letzte Änderung: 17. December 2006, 21:58 von nooooooooos »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #102 am: 17. December 2006, 22:19 »
Aber dabei musst du eben beachten, dass du in der Pipeline Brüche haben kannst, die du nicht hardwareseitig bearbeiten willst (=> Aufwand); das musst du dann im Assembler berücksichtigen. "JMP" wird dann zu "JMP NOP NOP", weil du ja nicht weißt, was die beiden folgenden Opcodes tun.
Hm, also den Assembler halte ich für den falschen Ort, sowas zu machen, der hat einfach meine Befehle 1:1 in Maschinencode zu übersetzen. Denn ich als proffesionel serious genuine Brotrö... Programmierer will die Delay Slots natürlich irgendwie sinnvoll nutzen, wann immer das möglich ist und mir nicht vom Assembler NOPs einbauen lassen, die eigentlich gar nicht nötig wären. Gerade bei den Sprüngen ist es für den Programmierer kein Problem, daran zu denken.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Termite

  • Beiträge: 239
    • Profil anzeigen
Gespeichert
« Antwort #103 am: 18. December 2006, 10:20 »
Moin

achtung bei piplining. wenn ihr nen jump oder call drin habt müst ihr eure pipline wieder löschen und von vorn beginnen. sonst wird das richtig kaotisch.

wobei schon piplining alleine zu richtig lustigen verhalten führen kann.  :-D
ich sach da nur AT91RM55800 und remap. (arm 7 kern mit 4 stufingen piplining)

folgender asm code.

FLASH: mov 0x12345678, 0x00000080 // remap auslösen
FLASH: jump 0x00000000 // irgendwohin springen; ab hier wird ins sram addresiert.

Adressen und werte sind mal egal. beim rempa wird die speicheraddressierung extern umgeschalten. Speicherbereiche werden quasi vertauscht, die cpu krigt davon nichts mit. Beim booten ist das insofern lustig, da im flash gestartet wird, und mit dem remap in den speicherbereich das interne SRam eingeblendet wird. sprich der jump der im flash steht dürfte eigentlich nach dem remap garnicht ausgeführt werden, da der ja nur im flash aber nicht im sram steht. aber aufgrund des piplinings. ist der jump bereits aus dem flash gelesen worden. befindet sich somit bereits im prozessor und kann trotzdem ausgeführt werden.  Gemein wirds erst dann wenn man genau die stelle versucht zu debuggen. ( hw debugger) da hat man dann kein piplining mehr und dann vereckt der ganze trick.

Somit überlegt euch beim piplining noch wie ihr mit z.B. nem software Monitorprogramm debuggen wollt? Gerade so sachen wie INT 3. da wird ja eigentlich nur ein befehl ausgetauscht durch nen in, damit der debugger angesprungen wird. anschliesend wird der int wieder überschrieben und durch den alten befehl ersetzt. IP wird zurückgesetzt und das programm wieder gestartet. Dadurch ist eure pipline nicht mehr korreckt und muss neu gefüllt werden.

sprich sobald von aussen sei es von debugger oder vom programmablauf selber der IP verändert wird muss die pipline neu aufgebaut werden. für mich hört sich das nach einiger zusätzlicher logik an.

gruss

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #104 am: 18. December 2006, 13:31 »
Naja is ja eigentlich ganz logisch: Sobald ein Register von den 2/3 nachfolgenden Befehlen gebraucht wird, muss die Pipeline gelöscht werden. Und da IP von jedem Befehl benötigt wird, gibt es halt da keine Ausnahmen.

Allerdings versteh ich nicht, warum die Pipeline gelöscht werden muss.
Nach einem JUMP...usw. sind einfach noch 2/3 NOPs in der Pipeline und das macht ja nix.

Ist eine 4-stufige Pipeline auch gut machbar? (Oder je mehr Stufen vorhanden sind, desto mehr kann man die Taktrate anziehen???)

Und warum kann ich die NOPs nicht vom Assembler einfügen lassen?? Ich muss doch logischerweise nach jedem JMP diese NOPs einfügen und zwar ohne wenn und aber => Eine gute maschinen-Arbeit
(Natürlich kann man mit dem vertauschen von Befehlen auch NOPs vermeiden...)


Gruss
Nooooooooooooos



kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #105 am: 18. December 2006, 13:38 »
Und warum kann ich die NOPs nicht vom Assembler einfügen lassen?? Ich muss doch logischerweise nach jedem JMP diese NOPs einfügen und zwar ohne wenn und aber => Eine gute maschinen-Arbeit
(Natürlich kann man mit dem vertauschen von Befehlen auch NOPs vermeiden...)
Eben. Ich kann nach dem jmp noch Befehle unterbringen, die ausgeführt werden sollen, egal ob gesprungen wird oder nicht. Nenn es Vertauschen oder wie auch immer, aber da muß nicht zwingend ein nop hin.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #106 am: 18. December 2006, 14:35 »
Ich muss taljeth da Recht geben, der Assembler muss es nicht zwingend tun. Allerdings würde ich es einfach so implementieren, weil ich es sonst irgendwo vergesse und den Fehler garantiert nicht finden würde :)

Meinetwegen kannst du da auch ein bisschen was dazwischenpfuschen lassen oder diese Funktion abschalten. Für mich ist halt ein Assembler vor der direkten Maschinensprache noch eine Ebene, in der man nicht mit den absoluten Innereien der CPU konfrontiert werden muss (aber kann, so man denn möchte). Außerdem kannst du JMP ja als eigenes Makro definieren. Optimieren kann man später immernoch.

Wieviele Stufen du deiner Pipeline gibst, ist dabei erstmal egal - aber mit zunehmender Tiefe wird die hardwareseitige Programmierung schwieriger (erst mit einer Hochsprache, z.B. C, wirst du die Probleme der Pipeline los).

Die Taktrate sollte bei der Überlegung erstmal keine Rolle spielen, aber deine Idee stimmt. Aber mehr als 1 Befehl / Takt willst du nicht implementieren :)

@Termite: Ich würde die Pipeline nie leeren, weil das, wie du sagtest, ein Haufen Logikarbeit ist. Meine Gedanken gehen halt da hin, dass im Programmablauf selbst schon die nötigen NOPs (oder halt andere Befehle) so eingearbeitet sind, dass die Pipeline nie geflusht werden muss. Dazu ist die Architektur zu einfach.
Hardwaredebugging würde ich nicht wie beim PC implementieren. Du kannst ja im Debugger immer die Befehle einzeln abarbeiten (also Befehl NOP NOP Befehl NOP NOP ...), aber ich würde einfach die Taktfrequenz von einem Taster erzeugen lassen (vgl. auch "homebrewcpu").

Gruß,
Svenska

Termite

  • Beiträge: 239
    • Profil anzeigen
Gespeichert
« Antwort #107 am: 18. December 2006, 15:01 »
wieso muss ich wenn ein register von den nächsten 2/3 befehlen verwendet wird ein nop einfügen bzw die pipline löschen? bei einer 4 stufingen pipline hätte ich folgende 4 stats

1. opcode decodieren
2. daten laden
3. execute comand
4. save data

wenn ich in state 3 ein register verändere das ein befehl der gearde in state 2 ist benötigt, dann muss ich ihn doch erst garnicht neu laden, sondern nur das ergebnis aus stat3 entsprechend übernemen wenn der befehl in den stat3 wechselt ( sicher aufwendiger ) aber da gibts sicher noch genug stoplersteine. Die pipline muss ich doch erst dann löschen, wenn falsche befehle drin stehen, die ich da nicht drinn sein sollen. (z.B. Jump) bei einem bedingten sprung kann es vorkommen, das falsche befehle drinstehen, muss aber nicht.

nur einfach gnadenlos nops einfügen ist irgendwo nicht sinn und zweck der sache. denn man arbeitet ja mit registern damit es schneller ist als dauernd den ram zu addressieren. aber bei 20Mhz ist das sowieso fast egal. zumindest bei SRAM, da der genausoschnell wie die register der cpu sind. der einzige zusätzliche aufwand ist die addressberechnung und die busumschaltung je nach dem was für ein speicherbuss verwendet wird.

gruss

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #108 am: 18. December 2006, 16:39 »
a) Opcode laden + decodieren => is klar
b) daten laden => welche daten? (Bei meinen Befehlen werden ausser bei mov nur Register oder Direktwerte akzeptiert)
c) execute command => OK
d) save data => welche daten? (ich hab mir das eben so gedcht, dass die ALU ohne Umweg über ein Ausgangsregister die Daten direkt in das entsprechende Register schreibt)

Somit wär das Pipelining nur noch 2stufig... Aber bringt es das??


Gruss
Noooooooooooos
« Letzte Änderung: 18. December 2006, 17:00 von nooooooooos »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #109 am: 18. December 2006, 17:16 »
Einfach und langsam: einstufige Pipeline (also keine).

Ich hätte eine einfache 3stufige Pipeline in Erwägung gezogen, nicht, um die Leistung/Taktfrequenz zu erhöhen, sondern primär, um den Aufbau zu vereinfachen und den einzelnen Komponenten mehr Zeit zu geben.

Um die Leistung ging es mir dabei nicht, sondern um die Trennung verschiedener Teile. Und NOPs vom Assembler primitiv einfügen ist imho die einfachste Möglichkeit, wenn auch die bei weitem langsamste.

@nooooooooos: Ob du eine 2- oder eine 4-stufige Pipeline bastelst, bleibt dir überlassen. Ob deine ALU auf die Prozessor-Register zugreifen kann oder nur auf interne Register (die dann natürlich extra geladen/gesichert werden müssen), ebenfalls. Häng dich nicht an der Pipeline auf, es geht auch ohne (das ist sogar einfacher). :)


Gruß,
Svenska

Termite

  • Beiträge: 239
    • Profil anzeigen
Gespeichert
« Antwort #110 am: 18. December 2006, 17:40 »
So

dann lass mal das noch mal anschauen.

1. ergebnis bleibt immer im Akku stehen und muss explizit in ein register verschoben werden. somit Ok. Somit kann es keine 3 addressmaschine mehr werden, da hierzu ein expliziter zwischenschrit notwendig ist. da sonst z.B. ax + bx = ax zu nem sehr lustigen verhalten fúhren kann quasi gleichzeitiges lesn und schreiben auf ein register. quasi ne loop in hw

2. die ALU arbeitet nur auf registern. und dem akku. somit 1 addressmaschine. Für eine 2 addressmaschine wird die verkabelung ohne zwischenspeicherung am alu eingang etwas komplex.  Die register sind ja nichts anderes als ram zellen, die über einen kleinen z.b. 4bit addresbuss angesprochen werden. die angesprochene speicherzelle wird dann auf den ALU-Eingagn geschaltet. die addresierung und bussleitungen brauchst du bei einer 2 addressmaschine somit 2 mal. da beide registerwerte gleichzeitig zur verknüpfung anliegen müssen. bei 16 registern geht das noch. je mehr das werden umso komplexer.

(sonderregister wie IP und PSW mal ausgenommen )

und wie kommen die daten aus dem programmcode in den akku?

gruss

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #111 am: 18. December 2006, 17:52 »
Ähm so ganz blick ich da nicht durch, aber du hast mich überzeugt, wenigstens ein Ausgangsregister an der ALU zu machen...

Damit dürfen aber in Zwei direkt aufeinander folgenden Befehlen nicht die selben Register verwendet werden.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #112 am: 18. December 2006, 18:13 »
Ich war jetzt in technischer Informatik nicht so der Held, aber das müßte doch passen, wenn du dann im nächsten Takt zurückschreibst und das zurückgeschriebene Register sofort wieder verwendest?

Wobei ich jetzt ehrlichgesagt eher eine Richtigstellung erwarte als Zustimmung. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Termite

  • Beiträge: 239
    • Profil anzeigen
Gespeichert
« Antwort #113 am: 18. December 2006, 18:46 »
nabend

die alu hat ja bekantlicherweise 2 Eingänge A und B. und einen ausgang nenen wir ihn mal C. Bei einer 3 Addressmaschine wird für A, B und C eine Addresse oder register angegeben. Daher auch der Name. Damit die ALU sauber arbeiten kann, muss für die ganze zeit der berechnung das eingangssignal A und B anliegen. nach einer gewissen zeit ( entsprechend der gatterlaufzeiten ) wird C das entsprechende ergebnis haben, das dann von einem Register übernommen wird. durch einen kurtzen tackt ein einem register gesichert. Soweit sollte das ja mal klar sein oder?

wird nun z.B. für B und C die gleiche adresse eingetragen, wird der ausgang auf den eingang geschaltet. wird da nicht irgend was dazwischen geschaltet fängt das system an zu schwingen, da sich das eingangsignal laufend ändert. Oder was sogar noch schlimmer währe, aufgrund der nutzung des gleichen datenbusses zu den registern, die irgendwelche leitunstreiber kurtz geschlossen. CPU rip  :oops:

somit muss das ergebnis erst einmal gesichert werden und nachdem die eingangssignale weggeschalten worden sind, und der datenbuss zu den registern nicht mehr belegt ist, in das register transferiert werden.

Bei einer einadress maschine ist es ja so, das nur eine addresse verwendet wird. Um nun alle ein und ausgange der alu su verarbeiten wird ein zusätzliches "register" verwendet der AKKU oder auch akkumolator. er nimmt die ergebnisse der berechnungen auf, und wird gleichzeitig auf einen der beiden eingänge geschaltet. Der 2te eingang ist somit über eine Addresse ansprechbar.

bei uns sa das so aus. der ausgang der ALU (C) ging auf die eingänge des AKKUs. die ausgänge waren auf dein eingang B beschleift. paralel dazu war ein leitungstreiberbaustein angeschlossen, der den akku ausgang auf den Datenbus zu den registern schalten konnte. Der baustein hat für den AKKU nur dann auf den Datenbuss eingekoppelt, wen der akku wert in ein register übertragen wurde, ansonsten war er vom bus abgekoppelt (tri-state). Der Datenbus selber war mit dem Eingag A der ALU verbunden, und dem Registerspeicher.

für eine berechnung lag ja quasi am ALU eingag B immer ein wert an. über die Registeradresse wurde ein register addresiert und der wert auf den Datenbuss geschaltet, und somit auf den ALU eingang A. wenn das ergebnis dann am AKKU eingang anlag, wurde ein clock signal ausgelöst, der das ergebnis in den AKKU übernommen hat. (passende flipflops verwenden)

zum sichern des akus wurde der registerspeicher auf write umgeschalten, somit war der datenbuss frei, und der AKKU wert konnte auf den bus geschalten werden.


wie genau eine 2-Addressmaschine definiert ist kann ich nicht sagen. 8086 ist glaub ich eine. opp a,b wobei addresse a meist doppelt verwendet wird sowohl als eingang als auch aus ausgang der alu

gruss




Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #114 am: 18. December 2006, 22:41 »
Damit dürfen aber in Zwei direkt aufeinander folgenden Befehlen nicht die selben Register verwendet werden.
Langsam verlier ich den Überblick :)

Wenn du Pipelining verwendest, darf ein Registerzugriff auf ein bestimmtes Register erst dann auftreten, wenn der vorhergehende Befehl vollständig abgeschlossen wurde. Das heißt, das zwischen

mov ax, 5
add ax, bx

2 NOPs gesteckt werden müssen (sofern du eine 3stufige Pipeline hast).

Wie gesagt, Termite kennt sich mit den technischen Grundlagen da am besten von uns aus (vermute ich mal :) ).

Und was ich sehr empfehlen kann, ist eine Simulation. Der Herr von myCPU hat ja auch eine timing-exakte Simulation geschrieben, in der jedes Gatter mit der dazugehörigen Gatterlaufzeit simuliert wurde. Damit lassen sich solche Schweinerei-Effekte wie halt Datenbus-Schwingungen recht schnell erkennen (und damit auch vermeiden). Glaube ich zumindest. :)

no*os: Benutzt du nun ein Programm zur Simulation, und wenn ja, welches?

Gruß,
Svenska

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #115 am: 19. December 2006, 18:45 »
Nee...bei der Simulation bin ich noch nicht...Erstens, weil ich zuerst den Befehlssatz mittels einer Emulation testen will, und zweitens, weil ich das Projekt eigentlich erst in nem halben Jahr richtig Starten will...

Hmm naja, wenn doch bei add ax,bx der Befehl schonmal gelanden und decodiert wird, solange die Register noch nicht stimmen, macht das ja nichts aus...

Gruss
Noooooooooos

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #116 am: 21. December 2006, 23:03 »
Zitat
Nee...bei der Simulation bin ich noch nicht...Erstens, weil ich zuerst den Befehlssatz mittels einer Emulation testen will, und zweitens, weil ich das Projekt eigentlich erst in nem halben Jahr richtig Starten will...

Das ist klar, aber ich glaube, ich würde erst schauen, welche Befehle sich überhaupt in annehmbarem Aufwand "basteln" lassen; besonders, wenn du keinen Microcode verwenden willst.

Zitat
Hmm naja, wenn doch bei add ax,bx der Befehl schonmal gelanden und decodiert wird, solange die Register noch nicht stimmen, macht das ja nichts aus...

Beim Laden und Decodieren des Befehls noch nicht, wohl aber beim Ausführen. Allerdings musst du vor dem Ausführen ja auch die zu addierenden Zahlen laden - und die kommen ja aus den Registern, von denen du nicht weißt, ob die Ergebnisse stimmen. Zum Decodieren eines Befehl gehören (so mein Verständnis der Materie) auch die Operanden, mit denen gearbeitet wird.
Also musst du zum Addieren auch darauf achten, dass die Pipeline keine so undefinierten/ungültigen Befehle ausführt - und dann macht es was aus.

Gruß,
Svenska

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #117 am: 22. December 2006, 17:55 »
Zum Decodieren eines Befehl gehören (so mein Verständnis der Materie) auch die Operanden, mit denen gearbeitet wird.
Meinst du jetzt, dass ich die Register schon beim Decodieren auf die ALU legen soll?? Dann würde es ja was ausmachen...
Aber das geht ja nicht, da die ALU für den aktuellen Befehl noch die alten Register braucht.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #118 am: 23. December 2006, 12:50 »
Wie du das alles baust, bleibt dir überlassen.
Ich hätte eher so daran gedacht, dass ich etwa folgendes Szenario habe:

In der ersten Stufe (Einlesen):
=> Befehl einlesen
=> Befehl decodieren
=> Operanden einlesen

In der zweiten Stufe (Ausführung):
=> Operanden in ALU-Register schreiben
=> ALU rechnen lassen
=> Ergebnis in ALU-Register schreiben

In der dritten Stufe (Ausgabe):
=> ALU-Register in Zielregister schreiben

Damit verschwende ich zwar etwas Rechenleistung in der dritten Stufe, habe aber die maximal mögliche Zeit in der zweiten Stufe. Damit werden geringere zeitliche Anforderungen an die ALU gestellt, die sich nicht mit den Prozessorregistern o.ä. rumschlagen muss. Dafür hat die ALU eben eigene Register, die somit in Nullzeit erreichbar sind, ohne externe Bus-Zugriffe und somit mit einer höheren Taktfrequenz.

Inwiefern das realisierbar ist, weiß ich nicht (eine Simulation habe ich noch nicht begonnen :) ).

Gruß,
Svenska

ST-225

  • Beiträge: 43
    • Profil anzeigen
Gespeichert
« Antwort #119 am: 30. May 2007, 09:40 »
Hat jetzt eigentlich schon jemand angefangen ?

 

Einloggen