Pascal "absolute" Deklaration - mit Pointer-Array möglich?

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Danke!

Wenn man die Architektur ein wenig versteht, ist Assembler die logischste und
einfachste "Sprache" überhaupt...
mov ax, 13h
int 10h

while vorne_frei do vor;
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von freecrac »

zatzen hat geschrieben:Danke!

Wenn man die Architektur ein wenig versteht, ist Assembler die logischste und
einfachste "Sprache" überhaupt...
Aus diesem Grund finde ich es auch nicht so schwer auf eine Hochsprache mit Variablen vollständig zu verzichten und ersatzweise dafür reservierte Speicheradressen zu verwenden. Genauso einfach wie man auf eine Variable über den Namen der Variable zugreifen kann, so können auch Speicheradressen einen Namen bekommen, womit es vergleichsweise verständlich wird wofür der Platz genutz werden soll. Hinter den Speicheradressen und den Befehlen können sonst auch noch Erklärungen für eine Berechnung mit einfachen Variablennamen notiert werden, damit man ein Abschnitt besser erkennen kann und was damit erzielt werden soll.

Dirk
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Zu folgendem hab ich eine kleine Verständnisfrage:
zatzen hat geschrieben:Ich frag mich nur ob es da nicht Einbußen mit der Geschwindkeit gibt, d.h. wenn man auf eine einzelne Variable zugreifen will, ob das dann wirklich genauso schnell ist als wenn man einfach auf ein normales Array zugreift? Du schriebst mal sowas, dass Units Sachen zwar modular und übersichtlich machen, aber u.U. langsamer sind als wenn man alles direkt ins Hauptprogramm schreibt.

(DOSferatu darauf:)
Das hast Du falsch verstanden. Gemeint ist: Wenn man VÖLLIG OHNE UNTERPROGRAMME (also ohne procedures/functions) arbeitet, hat man einen SEHR GERINGFÜGIGEN Geschwindigkeitsvorteil.
Erklärung: Werden Subroutinen aufgerufen, wird ja ein CALL ausgeführt und bei Verlassen derselben ein RET. (oder bei FAR CALLs eben RETF.) Die paar Taktzyklen, die für das Ausführen dieser beiden Befehle benutzt werden, sind der "Geschwindigkeitsnachteil".
Ich hatte dies nur der Vollständigkeit halber erwähnt.
Und zwar, wenn ich in einem Pascal-Programm Units verwende, kommen die dann alle ins Codesegment (CS)
und sind NEAR? Und ist Pascal auf 64K Code begrenzt oder kann man über Units den ganzen konventionellen
RAM belegen? Das Datensegment scheint ja auf 64K begrenzt zu sein.
mov ax, 13h
int 10h

while vorne_frei do vor;
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von wobo »

zatzen hat geschrieben:Zu folgendem hab ich eine kleine Verständnisfrage:

Und zwar, wenn ich in einem Pascal-Programm Units verwende, kommen die dann alle ins Codesegment (CS)
und sind NEAR? Und ist Pascal auf 64K Code begrenzt oder kann man über Units den ganzen konventionellen
RAM belegen? Das Datensegment scheint ja auf 64K begrenzt zu sein.
Das Datensegment für alle globalen Variablen ist bei Pascal, d.h. Tubro Pascal 4.0 - 7.0, ein einziges, max. 64kb großen Segment. Das Hauptprogramm und jede Unit bekommt ihr eigenes, jeweils max. 64kb großes Codesegment. Der Code kann also viele 64k-große Segmente umfassen. Wenn man nicht von Hand (z.B. per Compilerschalter) die Compilierung beeinflusst, dann sind alle procedures/functions des Hauptprogramms near calls. Alle procedures/functions einer Unit sind far calls, wenn Du die procedure/function auch im INTERFACE-Teil der Unit führst, damit sie dann von anderen Units bzw. dem Hauptprogramm aufgerufen werden können. Wenn Du procedures/functions "lokal" in einer Unit anlegst, d.h. sie nur im IMPLEMENTATION-Teil der Unit ausformulierst, sie aber nicht im INTERFACE-Teil deklarierst, dann werden diese procedures/functions als near calls aufgerufen.
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Alles klar.

Bleibt nur noch die Klärung dessen, warum mich überhaupt interessiert ob es FAR oder NEAR calls sind:

Dauert ein FAR-CALL bzw. RET länger, als ein NEAR ?


Das ganze wird beispielsweise darüber entscheiden, ob ich alle benötigten Funktionen in eine einzige
Unit reinschreibe, oder ob ich viele kleine Units habe die ich dann eben jeweils "use" .
mov ax, 13h
int 10h

while vorne_frei do vor;
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von wobo »

zatzen hat geschrieben: Dauert ein FAR-CALL bzw. RET länger, als ein NEAR ?
Ja. beim FAR CALL wird zu einer absoluten Segment:Offset-Adresse verzweigt. Es wird also sowohl das Register für das CodeSegment CS als auch der Instruction Pointer IP neu gesetzt. Das dauert länger als das bloße Verändern von IP beim NEAR CALL. Beim NEAR CALL wird ja nur innerhalb eines 64k-Segments gesprungen, so dass die Veränderung von nur IP ausreichend ist. Verlangsamend beim FAR CALL kommt noch hinzu, dass es sich bei CS um ein Segment-Register handelt. Deren Veränderung dauert meist noch überproportional länger als das Setzen/Verändern anderer Register.
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

DOSferatu hat geschrieben:Genau zu verstehen was man benutzt, finde ich lobenswert und unterstützenswert. Viel zu viele "Programmierer" benutzen Zeug, von dem sie keine Ahnung haben und können dann nicht damit umgehen, wenn das Programm/der Algorithmus usw auch nur die kleinste Änderung erfordert und dies das "Fertigbauteil" zufällig nicht in seiner Grundanordnung unterstützt.
Das ist ja überhaupt auch die wichtigste Motivation, warum ich überhaupt noch für DOS programmiere.
Es gibt heute jede erdenkliche Software und jedes Spiel schon in tausendfacher Ausführung von irgendwem
fertigprogrammiert, wenn ich nur dieses oder jene Programm haben wollte müsste ich nur mal im Internet
nachsehen.

Aber ich tu mir selber einfach den Gefallen, nachzuholen, was ich um 1990 verpasst habe, nämlich ansprechende
Spiele für DOS programmieren, und damals war das ja noch so, dass man keine fertigen Module hatte, sondern
jeder Spieleentwickler hat (wahrscheinlich) seine "Engine" oder was auch immer höchst selbst zusammengeschrieben.
Ich meine, das merkt man auch, damals hat sich jedes Spiel oder wenigstens jeder Spieleentwickler richtig
charakteristisch von den anderen abgesetzt.
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Nochmals vielen Dank an alle Helferlein!
Es ist ein gutes Gefühl, nicht mehr nur Halbwissen zu haben, man programmiert einfach sauberer.

Falls es jemand unterhaltsam findet, hier nach langer Zeit nicht ASM programmieren, meine Bitread-Function.
Ich habe sie noch nicht ausgiebig getestet, aber bei den paar Tests die ich gemacht habe hat's geklappt!
Kommt mir noch ein bisschen viel Code vor, vielleicht kann man da noch optimieren.

Code: Alles auswählen

procedure set_bitpointer(p: pointer);
begin
  bit_array_pointer := p;
  bitread_bytepos := 0;
  bitread_bitoffset := 0;
end;


function read_bits(length: byte): byte; assembler;
{
  to do:
  -----

  - word aus datenfeld einlesen
  - zurechtruecken und beschneiden
  - bytepos und bitoffset weiterzaehlen
}
asm

  mov bx, bitread_bytepos
  mov dl, bitread_bitoffset
  mov dh, length

  les si, bit_array_pointer
  add si, bx
  mov ax, es:[si]

  mov cl, dl
  shr ax, cl
  { zurechtgeschoben }

  mov cl, dh
  mov ch, 1  { hier stattdessen vielleicht lieber der zweizeiler " xor ch, ch ;  inc ch " ? }
  shl ch, cl
  dec ch
  { maske erstellt }

  and al, ch
  { maske anwenden (ueberschuessige bits oberhalb abschneiden) }

  mov ah, 8 { mit der 8 wird unten 2x hantiert, daher nehmen wir mal ah stattdessen }

  add dl, dh
  cmp dl, ah  { ah = 8 }
  jb @skip

  sub dl, ah  { ah = 8 }
  inc bx
  mov bitread_bytepos, bx

  @skip:

  mov bitread_bitoffset, dl

end;
Ich sehe schon, ich muss wohl BX nicht benutzen, kann wohl direkt die Speicherstelle nehmen.
Es sei denn, Operationen mit dem Register sind schneller und die MOVs auch sehr schnell.
Ich muss mir auch mal die Liste der Taktzyklen ausdrucken.
Und naja, anstatt mit einer "Maske" zu arbeiten könnte ich auch einfach AX einmal entsprechend
nach links und wieder rechts shiften, so dass die oberen Bits einfach rausfallen. Das ist aber
genausoviel Rechnerei wie bei der Maske, wenn nicht noch mehr bzw. langsamer.
mov ax, 13h
int 10h

while vorne_frei do vor;
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von freecrac »

Guten Morgen.
zatzen hat geschrieben:Nochmals vielen Dank an alle Helferlein!
Es ist ein gutes Gefühl, nicht mehr nur Halbwissen zu haben, man programmiert einfach sauberer.

Falls es jemand unterhaltsam findet, hier nach langer Zeit nicht ASM programmieren, meine Bitread-Function.
Ich habe sie noch nicht ausgiebig getestet, aber bei den paar Tests die ich gemacht habe hat's geklappt!
Kommt mir noch ein bisschen viel Code vor, vielleicht kann man da noch optimieren.

Code: Alles auswählen

procedure set_bitpointer(p: pointer);
begin
  bit_array_pointer := p;
  bitread_bytepos := 0;
  bitread_bitoffset := 0;
end;


function read_bits(length: byte): byte; assembler;
{
  to do:
  -----

  - word aus datenfeld einlesen
  - zurechtruecken und beschneiden
  - bytepos und bitoffset weiterzaehlen
}
asm

  mov bx, bitread_bytepos
  mov dl, bitread_bitoffset
  mov dh, length

  les si, bit_array_pointer
  add si, bx
  mov ax, es:[si]
Wenn SI nicht wieder verwendet wird, dann kann man die Addition mit BX auch in den Mov-Befehl mit einbauen.
les si, bit_array_pointer
mov ax, es:[si+bx]

Code: Alles auswählen

  mov cl, dl
  shr ax, cl
  { zurechtgeschoben }
Der Code soll wohl für einen 80286 ausführbar sein, weil ab 80386 könnte man sonst auch ein "shr ax, dl" verwenden.
(Ich selber bin es gar nicht mehr so gewohnt solche Einschränkungen zu berücksichtigen.)

Code: Alles auswählen

  mov cl, dh
  mov ch, 1  { hier stattdessen vielleicht lieber der zweizeiler " xor ch, ch ;  inc ch " ? }
Ich meine ein "xor ch, ch" zusammen mit "inc ch" macht an dieser Stelle nicht so viel Sinn und ich würde es bei "mov ch, 1" belassen. Gemessen welche Variante davon schneller ist habe ich aber noch nicht.

;-------------------
Wenn man aber vorher mit CX arbeitet und der gesamte Inhalt von CX nicht mehr benötigt wird und wenn man dann danach nur CL und/oder CH verwenden möchte, also von einem 16 Bit-Register zu einem 8 Bit-Register wechselt, dann macht es einen Sinn vorher ein "xor cx, cx" zu verwenden und unmittelbar danach das 8 Bitregister mit einem Wert zu laden. (Das gilt auch für ax, bx und dx und auch beim Wechsel von einem 32 Bit-Register zu einem 16 Bit-Register vom selben grösseren Register.)

Ein Beispiel welches mit deinem Code zwar nichts zu tun hat, aber meine spezielle Erklärung zur Verwendung vom XOR-Befehl anschaulicher machen soll:

Code: Alles auswählen

mov cx, Wert
add cx, ax
mov dx, cx       ; ab hier wird der Inhalt von CX nicht mehr benötigt

xor cx, cx       ; vor dem Wechsel zu einem 8 Bit-Register
mov cl, Wert
....
Und anderes herum:

Code: Alles auswählen

xor cx, cx      ; vor dem Wechsel zu einem 8 Bit-Register
mov ch, Wert
....
Das "xor cx, cx" bewirkt hierbei das ein unmittelbar nachfolgender 8 Bit-Befehl(vom selben grösseren Registers) beim Wechsel schneller ausgeführt werden kann. Das hat was mit der internen Verarbeitung der Befehle zu tun, wobei ein "xor Register, Register" beim Wechsel zu einem kleineren Register eine Sonderrolle ein nimmt, auch wenn es sonst nichts anderes bewirkt und überflüssig zu sein scheint.
;-------------------

Code: Alles auswählen

  shl ch, cl
  dec ch
  { maske erstellt }

  and al, ch
  { maske anwenden (ueberschuessige bits oberhalb abschneiden) }

  mov ah, 8 { mit der 8 wird unten 2x hantiert, daher nehmen wir mal ah stattdessen }
Ja, das macht Sinn.

Code: Alles auswählen

  add dl, dh
  cmp dl, ah  { ah = 8 }
  jb @skip

  sub dl, ah  { ah = 8 }
  inc bx
  mov bitread_bytepos, bx

  @skip:

  mov bitread_bitoffset, dl

end;
Ich sehe schon, ich muss wohl BX nicht benutzen, kann wohl direkt die Speicherstelle nehmen.
Weil die Adresse von "bitread_bytepos" aber auch an anderer Stelle benötigt wird, deswegen ist es sinnvoll dafür BX zu verwenden.
Es sei denn, Operationen mit dem Register sind schneller und die MOVs auch sehr schnell.
Operationen im Speicher werden immer langsamer als in Registern ausgeführt, aber ich denke das ein "inc Speicheradresse" anstelle von "inc Register" + "mov Speicheradtresse, Register" wohl schneller ausgeführt wird, weil in beiden Fällen ein Speicherzugriff erfolgt.
Ich muss mir auch mal die Liste der Taktzyklen ausdrucken.
Und naja, anstatt mit einer "Maske" zu arbeiten könnte ich auch einfach AX einmal entsprechend
nach links und wieder rechts shiften, so dass die oberen Bits einfach rausfallen. Das ist aber
genausoviel Rechnerei wie bei der Maske, wenn nicht noch mehr bzw. langsamer.
Das mag sein, ich habe mir den Vorgang noch gar nicht genau angeschaut.

Dirk
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Danke!

Soweit ich weiss, unterstützt Pascal ja nur direkt 286er Assembler.
Bzw. muss man sich den ja sogar noch mit $G+ freischalten, sonst
kann man nur 8086er Code erzeugen.

32 Bit Code scheint so nicht integriert zu sein, ist ja auch nachvollziehbar,
als Turbo Pascal 7.0 gemacht wurde war das noch kein Standard.
Obwohl - ich lese gerade nach, 386er Prozessoren gibt es seit 1985,
also hätte man das durchaus integrieren können...
les si, bit_array_pointer
mov ax, es:[si+bx]
Ich nehme mal an, das ist kompakter formuliert, dürfte aber ähnlich schnell sein als wenn ich
si explizit um bx erhöhe (?). Aber nochmal gut zu wissen, dass man das so machen kann, damit
ergeben sich ja flexiblere Möglichkeiten als wenn man si wirklich immer verändern muss.
Das "xor cx, cx" bewirkt hierbei das ein unmittelbar nachfolgender 8 Bit-Befehl(vom selben grösseren Registers) beim Wechsel schneller ausgeführt werden kann. Das hat was mit der internen Verarbeitung der Befehle zu tun, wobei ein "xor Register, Register" beim Wechsel zu einem kleineren Register eine Sonderrolle ein nimmt, auch wenn es sonst nichts anderes bewirkt und überflüssig zu sein scheint.
Das ist wohl eine nicht zu unterschätzende Wissenschaft für sich, in die ich so noch überhaupt keinen Einblick
habe und auch nicht weiss wo ich dazu Informationen finden könnte. Ich habe das in anderen Threads schon mitverfolgt,
dass je nachdem wie man die ASM Befehle anordnet sich ganz verschiedene Geschwindigkeiten ergeben können.
Kommt mir sehr komplex vor, aber vielleicht ist es das gar nicht. Bisher war ich erstmal froh, überhaupt mit Assembler
eine "Hochgeschwindigkeitssprache" zu haben, aber es ist wohl noch komplexer...
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Ich probiere das gerade mit den Stack-Registern...
Man kann auch innerhalb einer Subroutine die Register SP/BP und SS frei verwenden, wenn man die Werte darin vorher an eine reservierte Speicherstelle sichert und am Ende der Subroutine wieder herstellt. Genauso muss man verfahren, wenn wir innerhalb unserer Subroutine noch weitere Subroutinen aufrufen möchten, dann müssen vorher auch die Register wieder hergestellt sein, damit der Zustand unseres Stacks funktionstüchtig bleibt und auch für unsere call-Befehle die Rücksprungadressen für unsere weiteren Subroutinen aufnehmen kann.

Zwischenzeitlich wenn der Stack nicht weiter von uns verwendet wird können wir die Register SP/BP und SS auch für unsere eigenen Zwecke verwenden. Dann haben wir gleichzeitig mit DS:SI und ES:DI auch noch SS:SP, oder SS:BP zur Adressierung von verschiedenen Speicherbereichen zur Verfügung an deren Adressen sich Tabellen etc. befinden können.
Pascal lässt es nicht zu, dass ich sowas wie " mov ax, ss:[sp] " schreibe. Vielleicht stell ich mich nur dumm an.
" mov ax, ss:[bx] " oder "...ss:[4711] " geht aber. Scheint mir halt nur, ich kann die Stacksegment-Register
benutzen, aber nicht die Offsets. Oder ich weiss eben noch nicht genug. Hey, aber ss:[bp] geht!
Wie ich das derzeit sehe, würde ich, wenn ich die Stack-Register verwende, DS in Ruhe lassen müssen, wenn ich
wirklich einen Gewinn erzielen möchte durch Ablegen von Registern an Speicherstellen. Kann ja nur mit unverändertem
DS auf Speicherstellen zugreifen - klar könnte ich DS z.B. in DX sichern, aber dann ist ja DX belegt...
Naja mal sehen.

Nebenbei würde mich ein kurzer Abriss darüber interessieren, wie wobo die Mixing-Routine in seinem MOD-Player
realisiert hat. Ich selbst hätte drei Speicherbereiche zu adressieren: Das Sample als Quelle, eine Tabelle für die
endgültigen Samplewerte, und den Puffer wo alles reingerechnet wird. Wenn da nicht noch was dazukommt.
DS werd ich wohl brauchen, denn ich habe ja viele Parameter als Daten beim Berechnen. Zwischendurch ne
Routine aufrufen muss ich eventuell auch, je nachdem wie ich das aufbaue.
mov ax, 13h
int 10h

while vorne_frei do vor;
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von wobo »

zatzen hat geschrieben: Nebenbei würde mich ein kurzer Abriss darüber interessieren, wie wobo die Mixing-Routine in seinem MOD-Player
realisiert hat. Ich selbst hätte drei Speicherbereiche zu adressieren: Das Sample als Quelle, eine Tabelle für die
endgültigen Samplewerte, und den Puffer wo alles reingerechnet wird. Wenn da nicht noch was dazukommt.
DS werd ich wohl brauchen, denn ich habe ja viele Parameter als Daten beim Berechnen. Zwischendurch ne
Routine aufrufen muss ich eventuell auch, je nachdem wie ich das aufbaue.
Ich hatte Glück: Ich hatte nur einen Pointer auf die Sample-Quelle (es:[di]) und der Rest (Parameter, Vermix-Buffer, kleine Volumetable von 4kb) war alles im Datensegment. Mein Vermix-Buffer ist nämlich sehr klein (<1k), da ich ihn gerade so groß gewählt hatte, dass er einmal pro Vertical Retrace aufgerufen wird, um Sync-Probleme mit der VGA zu vermeiden. Dadurch musste ich DS während des Vermixens nicht verändern, verliere aber knapp 8 kb an globalen Variablen.

Für größere Speicherbereiche würde ich halt auf GS und FS ausweichen - ich gehe davon aus, dass Dein Player ohnehin einen 386er voraussetzt. Ich hatte mir damals nur aus "sportlichen"/"ästhethischen" Gründen zum Ziel gesetzt, dass mein Player ausschließlich 286er-Befehle verwenden darf. Ich würde das aber heute nicht mehr so machen.
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von freecrac »

zatzen hat geschrieben:
les si, bit_array_pointer
mov ax, es:[si+bx]
Ich nehme mal an, das ist kompakter formuliert, dürfte aber ähnlich schnell sein als wenn ich
si explizit um bx erhöhe (?).
Solche Adressberechnungen [si+bx] werden schneller ausgeführt als "add si, bx".
Daher ist es ja auch sinnvoll ersatzweise "lea si, [si+bx]" anstelle von "add si, bx" zu nehmen, oder wie oben gleich mit "mov ax, es:[si+bx]", wenn wir das Ergebniss von SI+BX nirgendwo anders mehr brauchen.

Anstelle von "inc bx" nimmt man lieber "lea bx, [bx+1]". Nur werden mit lea keine Flags im Flagregister gesetz.
Das "xor cx, cx" bewirkt hierbei das ein unmittelbar nachfolgender 8 Bit-Befehl(vom selben grösseren Registers) beim Wechsel schneller ausgeführt werden kann. Das hat was mit der internen Verarbeitung der Befehle zu tun, wobei ein "xor Register, Register" beim Wechsel zu einem kleineren Register eine Sonderrolle ein nimmt, auch wenn es sonst nichts anderes bewirkt und überflüssig zu sein scheint.
Das ist wohl eine nicht zu unterschätzende Wissenschaft für sich, in die ich so noch überhaupt keinen Einblick
habe und auch nicht weiss wo ich dazu Informationen finden könnte. Ich habe das in anderen Threads schon mitverfolgt,
dass je nachdem wie man die ASM Befehle anordnet sich ganz verschiedene Geschwindigkeiten ergeben können.
Wenn wir 16 Bit aus dem Speicher laden, oder schreiben und es ist eine ungerade Adresse wo der Zugriff erfolgt , dann kann der Code nicht so schnell verarbeitet werden. Das gilt besonders für Datenzugriffe, aber auch Sprungadressen z.B von Subroutinen.

Wenn ich mich richtig erinnere werden ab Pentium schon 2 Befehle gleichzeitig verarbeitet. Aber nicht jeder Befehl läßt sich paaren. Wenn Abhängigkeiten zwischen den Befehlen bestehen, kann es ebenfalls zur Verzögerung kommen.
Sonst gilt die Regel: Schreibzugriffe unmittelbar nach einem Lesezugriff auf ein Register machen keine Probleme, aber Lesezugriffe unmittelbar nach einem Schreibzugriff.

Beispiele:
Diese Anordnung sollte man vermeiden:

Code: Alles auswählen

mov ax,12  ; AX beschreiben
mov bx,ax  ; AX unmittelbar danach wieder auslesen --vorher Wartezeit
           ; bis vorheriger Befehl vollständig ausgeführt--
mov cx,4   ; CX beschreiben
mov dx,cx  ; CX unmittelbar danach wieder auslesen --vorher Wartezeit
           ; bis vorheriger Befehl vollständig ausgeführt--
mov si,77  ; usw....
mov di,si
Und stattdessen lieber diese Anordnung nehmen:

Code: Alles auswählen

mov ax, 12
mov cx, 4   ; Befehl kann sofort ausgeführt werden während der vorherige noch verarbeitet wird.
            ; Es besteht keine Abhängigkeit zum vorherigen Befehl.
mov si, 77  ; usw... 
mov bx, ax
mov dx, cx
mov di, si
Kommt mir sehr komplex vor, aber vielleicht ist es das gar nicht. Bisher war ich erstmal froh, überhaupt mit Assembler
eine "Hochgeschwindigkeitssprache" zu haben, aber es ist wohl noch komplexer...
Ein klein wenig.

Dirk
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von zatzen »

Okay, das mit der Anordnung der Zugriffe für schnellere Abarbeitung lässt sich ja verstehen, das ist schön.

Was 386er Code angeht, möchte ich vielmehr wegen der Darstellung in Pascal bei 16 Bit bleiben...
Es ist eine Sache, aus AX ein EAX zu machen durch ein "db $66" davor, aber sicher noch eine ganz andere,
Register wie FS und GS kryptisch zu codieren...

Irgendwie blöd dass man inc/dec eines 16 Bit Registers bei nicht-Benötigen der FLags immer durch
einen LEA-Befehl ersetzen sollte...
Aber wenn es damit schneller ist, muss es wohl so sein.
mov ax, 13h
int 10h

while vorne_frei do vor;
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic

Beitrag von freecrac »

zatzen hat geschrieben:Okay, das mit der Anordnung der Zugriffe für schnellere Abarbeitung lässt sich ja verstehen, das ist schön.

Was 386er Code angeht, möchte ich vielmehr wegen der Darstellung in Pascal bei 16 Bit bleiben...
Es ist eine Sache, aus AX ein EAX zu machen durch ein "db $66" davor, aber sicher noch eine ganz andere,
Register wie FS und GS kryptisch zu codieren...

Code: Alles auswählen

 Ein Prozessorbefehl setzt sich aus bis zu neun Komponenten zusammen:
   Instruction Prefix                0 oder 1 Byte
   Address-Size Prefix               0 oder 1 Byte
   Operand-Size Prefix               0 oder 1 Byte
   Segment-Override Prefix           0 oder 1 Byte
   Opcode                            1 oder 2 Byte
   Mod R/M                           0 oder 1 Byte
   SIB, Scale Index Base (386+)      0 oder 1 Byte
   Displacement                      0, 1, 2 oder 4 Byte (4 nur 386+)
   Immediate                         0, 1, 2 oder 4 Byte (4 nur 386+)
;------------------
Address-Size Prefix (67H)
Operand-Size Prefix (66H)

Segment-Override Prefixe:
   26h   ES Override
   2eh   CS Override
   36h   SS Override
   3eh   DS Override
   64h   FS Override (386+)
   65h   GS Override (386+)
Defaultmässig wird bei den meisten Operationen mit Zugriff auf den Speicher DS als Segment-Register zugeordnet und ein DS Override Prefix (3Eh) wird nur benötigt wenn (E)SP, oder (E)BP als Adressregister verwendet werden sollen, oder wenn zum Beispiel bei einem Stringbefehl wie "stosb, stosw, oder stosd" nicht das ES-Segmentregister, sondern DS verwendet werden soll.

...

Ich meine nur ein Segment-Override Prefix einzufügen ist nicht so schwer. Etwas schwerer ist es das Postbyte(Mod R/M-Byte) für einen 32 Bit-Befehl mit SIB + Displacement von Hand zu cooden.

Hier noch einmal einige Tabellen dafür:

Code: Alles auswählen

Format of Postbyte(Mod R/M aus Intel-Doku)
------------------------------------------
MM RRR MMM

MM  - Memeory addressing mode
RRR - Register operand address
MMM - Memoy operand address

RRR Register Names
Filds  8bit  16bit  32bit
000    AL     AX     EAX
001    CL     CX     ECX
010    DL     DX     EDX
011    Bl     BX     EBX
100    AH     SP     ESP
101    CH     BP     EBP
110    DH     SI     ESI
111    BH     DI     EDI

---

16bit memory (No 32 bit memory address prefix)
MMM   Default MM Field
Field Sreg     00        01          10             11=MMM is reg
000   DS       [BX+SI]   [BX+SI+o8]  [BX+SI+o16]
001   DS       [BX+DI]   [BX+DI+o8]  [BX+DI+o16]
010   SS       [BP+SI]   [BP+SI+o8]  [BP+SI+o16]
011   SS       [BP+DI]   [BP+DI+o8]  [BP+DI+o16]
100   DS       [SI]      [SI+o8]     [SI+o16]
101   DS       [DI]      [DI+o8]     [SI+o16]
110   SS       [o16]     [BP+o8]     [BP+o16]
111   DS       [BX]      [BX+o8]     [BX+o16]
Note: MMM=110,MM=0 Default Sreg is DS !!!!

32bit memory (Has 67h 32 bit memory address prefix)
MMM   Default MM Field
Field Sreg     00        01          10             11=MMM is reg
000   DS       [EAX]     [EAX+o8]    [EAX+o32]
001   DS       [ECX]     [ECX+o8]    [ECX+o32]
010   DS       [EDX]     [EDX+o8]    [EDX+o32]
011   DS       [EBX]     [EBX+o8]    [EBX+o32]
100   SIB      [SIB]     [SIB+o8]    [SIB+o32]
101   SS       [o32]     [EBP+o8]    [EBP+o32]
110   DS       [ESI]     [ESI+o8]    [ESI+o32]
111   DS       [EDI]     [EDI+o8]    [EDI+o32]
Note: MMM=110,MM=0 Default Sreg is DS !!!!

---

SIB is (Scale/Base/Index)
SS BBB III
Note: SIB address calculated as:
<sib address>=<Base>+<Index>*(2^(Scale))

Fild   Default Base
BBB    Sreg    Register   Note
000    DS      EAX
001    DS      ECX
010    DS      EDX
011    DS      EBX
100    SS      ESP
101    DS      o32        if MM=00 (Postbyte)
SS      EBP        if MM<>00 (Postbyte)
110    SS      ESI
111    DS      EDI

Fild  Index
III   register   Note
000   EAX
001   ECX
010   EDX
011   EBX
100              never Index SS can be 00
101   EBP
110   ESI
111   EDI

Fild Scale coefficient
SS   =2^(SS)
00   1
01   2
10   4
11   8
Dirk
Antworten