Pascal "absolute" Deklaration - mit Pointer-Array möglich?
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
Danke!
Wenn man die Architektur ein wenig versteht, ist Assembler die logischste und
einfachste "Sprache" überhaupt...
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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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.zatzen hat geschrieben:Danke!
Wenn man die Architektur ein wenig versteht, ist Assembler die logischste und
einfachste "Sprache" überhaupt...
Dirk
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
Zu folgendem hab ich eine kleine Verständnisfrage:
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.
Und zwar, wenn ich in einem Pascal-Programm Units verwende, kommen die dann alle ins Codesegment (CS)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 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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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.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.
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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" .
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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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.zatzen hat geschrieben: Dauert ein FAR-CALL bzw. RET länger, als ein NEAR ?
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
Das ist ja überhaupt auch die wichtigste Motivation, warum ich überhaupt noch für DOS programmiere.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.
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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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.
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.
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
- zurechtruecken 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;
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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
Guten Morgen.
les si, bit_array_pointer
mov ax, es:[si+bx]
(Ich selber bin es gar nicht mehr so gewohnt solche Einschränkungen zu berücksichtigen.)
;-------------------
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:
Und anderes herum:
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.
;-------------------
Dirk
Wenn SI nicht wieder verwendet wird, dann kann man die Addition mit BX auch in den Mov-Befehl mit einbauen.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 - zurechtruecken 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]
les si, bit_array_pointer
mov ax, es:[si+bx]
Der Code soll wohl für einen 80286 ausführbar sein, weil ab 80386 könnte man sonst auch ein "shr ax, dl" verwenden.Code: Alles auswählen
mov cl, dl shr ax, cl { zurechtgeschoben }
(Ich selber bin es gar nicht mehr so gewohnt solche Einschränkungen zu berücksichtigen.)
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.Code: Alles auswählen
mov cl, dh mov ch, 1 { hier stattdessen vielleicht lieber der zweizeiler " xor ch, ch ; inc ch " ? }
;-------------------
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
....
Code: Alles auswählen
xor cx, cx ; vor dem Wechsel zu einem 8 Bit-Register
mov ch, Wert
....
;-------------------
Ja, das macht Sinn.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 }
Weil die Adresse von "bitread_bytepos" aber auch an anderer Stelle benötigt wird, deswegen ist es sinnvoll dafür BX zu verwenden.Ich sehe schon, ich muss wohl BX nicht benutzen, kann wohl direkt die Speicherstelle nehmen.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;
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.Es sei denn, Operationen mit dem Register sind schneller und die MOVs auch sehr schnell.
Das mag sein, ich habe mir den Vorgang noch gar nicht genau angeschaut.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.
Dirk
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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...
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.
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...
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...
Ich nehme mal an, das ist kompakter formuliert, dürfte aber ähnlich schnell sein als wenn ichles si, bit_array_pointer
mov ax, es:[si+bx]
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 ist wohl eine nicht zu unterschätzende Wissenschaft für sich, in die ich so noch überhaupt keinen EinblickDas "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.
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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
Ich probiere das gerade mit den Stack-Registern...
" 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.
Pascal lässt es nicht zu, dass ich sowas wie " mov ax, ss:[sp] " schreibe. Vielleicht stell ich mich nur dumm an.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.
" 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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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.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.
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.
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
Solche Adressberechnungen [si+bx] werden schneller ausgeführt als "add si, bx".zatzen hat geschrieben:Ich nehme mal an, das ist kompakter formuliert, dürfte aber ähnlich schnell sein als wenn ichles si, bit_array_pointer
mov ax, es:[si+bx]
si explizit um bx erhöhe (?).
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.
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.Das ist wohl eine nicht zu unterschätzende Wissenschaft für sich, in die ich so noch überhaupt keinen EinblickDas "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.
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 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
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
Ein klein wenig.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...
Dirk
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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.
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;
int 10h
while vorne_frei do vor;
Re: Pascal "absolute" Deklaration - mit Pointer-Array möglic
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+)
...
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