Hier geht es um einige Optimierungen am Programm der vorigen Webseite.Stringbefehl und Ausrichten auf DoppelwortgrenzeBeim Merkmal ha00 steht diese Befehlsfolge: cld ;richtung aufwaerts ha00: lea edi,dz ;"druckzeile" mov ecx,llz @@: mov al,[esi] mov [edi],al inc esi inc edi loop @BZwischen @@ und dem loop @B wird jedes Byte der dz Druckzeile durch ein korrespondierendes Byte aus der Leerzeile lz überschrieben. Dazu werden 5 Befehle verwendet und die Druckzeile ist 81 Bytes lang: Es werden 405 Befehle ausgeführt. Zur Ausführung genau dieser Aufgabe gibt es jedoch spezielle Befehle in der Klasse der Stringbefehle. Es passt der Stringbefehl movsb mit vorgestelltem Wiederholungspräfix rep. Damit es in der richtigen Reihenfolge von links nach rechts abläuft, muss das Richtungsflag passend gesetzt sein. Das wird durch den Befehl cld erreicht. So sieht der Programmteil nach der Änderung aus: cld ;richtung aufwaerts push ds ;ermoeglich die Verwendung von ret movsb pop es ha00: lea edi,dz ;"druckzeile" mov ecx,llz rep movsbIn diesem Fall wird movsb 81-mal ausgeführt. Das sind 324 Befehlsausführungen weniger als in der vorhergehenden Version. Allerdings greifen die modernen Prozessoren nicht auf einzelne Bytes aus dem Hauptspeicher zu. Sie schnappen sich vier Bytes auf einmal. Wenn man dies ausnutzt, könnte man mit einem Viertel der Befehlsausführungen auskommen. Allerdings muss man aufrunden, denn 81/4 ergibt einen Rest. Glücklicherweise kann das Assemblierprogramm rechnen. (81 + 3)/4 ergibt die gewünschte Anzahl Wiederholungen. Das zugeordnete Symbol ist im Bereich .data definiert und heißt llz4: llz equ $ - lz llz4 equ (llz+3)/4Wenn nun statt movsb das passende movsd verwendet wird, kommen wir mit 21 Befehlsausführungen aus. Allerdings funktioniert anschließend das Programm nicht mehr, denn die letzte Übertragung überschreibt den Inhalt des Arbeitsfeldes dzpos (vergleiche Programmliste auf der vorhergehenden Seite). Man müsste zusätzlich drei „Schutzbytes” hinter der Druckzeilendefinition im Datenbereich definieren. Das lassen wir jedoch sein, denn es gibt eine bessere Möglichkeit! cld ;richtung aufwaerts push ds ;ermoeglich die Verwendung von ret movsd pop es ha00: lea edi,dz ;"druckzeile" mov ecx,llz4 rep movsdDie bessere Möglichkeit ist die Verwendung der Direktive ALIGN. Sie wurde geschaffen, weil man sich sonst nicht aussuchen kann, mit welcher zusammenhängenden Gruppe von 4 zusammenhängenden Bytes sich der movsd beschäftigt. Wenn die vier zusammenhängenden Bytes auf einer durch 4 ohne Rest teilbaren Speicheradresse stehen, reicht ein Speicherzugriff aus. Tun sie es nicht, führt movsd sind zwei aufeinanderfolgende Zugriffe aus. Dies gilt für das Lesen und auch für das Schreiben. ALIGN 4 fügt für die Ausrichtung passende Schutzbytes hinzu. Die folgende Tabelle zeigt es.
Bei dem ersten ALIGN 4 ist keine Ausrichtung erforderlich, denn das nächste Feld lz beginnt auch ohne zusätzliche Ausrichtung auf einer durch 4 ohne Rest dividierbaren Speicheradresse: 0b8h entspricht dezimal 168. Das ab 0B8h definierte Textfeld lz ist 51h Bytes lang. Ohne das ALIGN 4 wurde das nachfolgende Textfeld dz ab Adresse 109h beginnen: 0b8h + 51h = 109h 109h (entspricht 265 dezimal) und ist somit nicht ohne Rest durch 4 teilbar. In diesem Fall wird durch das ALIGN 4 auf die nächste ohne Rest durch 4 teilbare Speicheradresse vorgerückt. Es ist die Speicheradresse 10Ch, entsprechend 268 dezimal. Zwei Tabellenzeilen beginnen mit einem Gleichheitszeichen. Sie zeigen die Werte, die die beiden Symbole llz und llz4 erhalten. Die Symbole geben die Anzahl Wiederholungen der Übertragungen an. |
Der alte SchiebebefehlTeile des Programmes stammen noch aus der Zeit der 8086. Seitdem sind einige Assemblerbefehle hinzugekommen und einige alte Assemblerbefehle wurden um zusätzlich Möglichkeiten erweitert. Dazu gehört der Befehl shr. Beim 8086 konnte man ohne Vorbereitung nur um 1 Bit rotieren. Deshalb steht im Programmtext der Befehl 4-mal untereinander. Ab dem 80186 kann man mit einem shr bis zu 31 Schiebetakte ausführen. Die vier Schiebebefehle lassen sich somit durch einen einzigen shr al,4 ersetzen.Schaut man sich den im Quelltext folgenden Programmteil an, stellt man fest: Dass Register ah wird nicht verändert. Somit kann man die Sicherung des Registerpaares ax im Stack durch die schneller ausgeführte Sicherung des Registers al in ah ersetzen. Die Tabelle zeigt den betreffenden Programmabschnitt vor und nach der Optimierung: | |
byte_hex: push ax shr al,1 shr al,1 shr al,1 shr al,1 call byte_hex1 pop ax | byte_hex: mov ah,al shr al,4 call byte_hex1 mov al,ah |
Auch in dem Unterprogramm pa00 gibt es Verbesserungsmöglichkeiten. Die vorsorgliche Sicherung des Registers ecx kann ersatzlos entfallen. Beim Register ebx ist sie erforderlich, denn im Unterprogramm byte_hex wird ebx verändert. Wenn man jedoch edx verwendet, dann spart man die Stacksicherung von ebx ein. | |
;Unterprogramm zur 4-stelligen Adressausgabe ;(8 Hexadezimalziffern) pa00: lea ebx,dz ;Anfangsadresse Druckzeile mov dzpos,ebx mov ebx,offset address + 3 mov ecx,4 ;Adresse vierstellig hexa @@: push ecx ;ausgeben (rueckwaerts) mov al,[ebx] dec ebx push ebx ;Upro byte_hex zerstoert ebx call byte_hex pop ebx pop ecx loop @B ret | ;Unterprogramm zur 4-stelligen Adressausgabe ;(8 Hexadezimalziffern) pa00: lea edx,dz ;Anfangsadresse Druckzeile mov dzpos,ebx mov edx,offset address + 3 mov ecx,4 ;Adresse vierstellig hexa @@: ;ausgeben (rueckwaerts) mov al,[ebx] dec edx call byte_hex loop @B ret |