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
- 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]
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]
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