SelfOptimize - MC680x0

*** Selbstoptimierender Assemblercode ? Klar, kein Problem ! ***

Als ich mit Piranha (grüße !) ein paar Mails schrieb und mich mit Splines beschäftigte (Die Propellerteile die in "Static Chaos"  rumfliegen),
ärgerte ich mich darüber wieviel Zyklen nur allein für die eigentlich unnötigen Befehle (Iterationscounter, Verzweigungen etc) draufgehen,
und ich dachte mir eine möglichkeit aus dieses Ballast abzuwerfen, durch selbstoptimierenden Code.
*** Download ***

;
;$VER: SelfOptimize.asm 1.05 am 27.4.92 (c) Holger.Hippenstiel.org - lynxx@uni.de
;
;Erdacht und verwendet für "The Silents - Static Chaos" Trackmo, relase 7/92.
;
;Dies ist eine Routine, die per Trace-Exception Programme optimieren kann,
;so eine Art "Just in Time" Compiler. Wäre Beispielsweise diese Programm gegeben:
;
;       lea     Count(pc),a3
;Loop:  bsr.b   Unter
;       subq    #1,(a3)
;       bcc.b   Loop
;       rts
;Unter: addq    #1,(a0)+
;       rts
;Count: dc.w       2

;Und würde diesen Optimierer durchlaufen, würde nur
;
;       addq    #1,(a0)+
;       addq    #1,(a0)+
;       rts
;
;übrigbleiben.
:
;Die übernommenen Befehle können je nach Anforderung im "TraceWatcher" angepasst werden.
;
;Assembler-Kompabilität:
;+AsmOne, AsmPro, DevPac [Default Type = word], MasterSeka & Profimat
;+Mindest 68010-Assemblier-Modi erforderlich.
;-Ungetestet: A68k
;

_LVOSuperVisor = -30                            ;SuperVisor modus aktivieren
AttnFlags      = 296                            ;Prozessor-Flags in der ExecBase

SelfOptimizer:
        move.l  4.w,a6                          ;ExecBase holen
        lea     Optimize(pc),a5                 ;Routine für SuperVisor-Modus
        jsr     _LVOSuperVisor(a6)              ;Sprung in SuperVisor-Routine
        move.l  a2,d0                           ;Ende Gelände, das Erzeugte Programm steht
        rts                                     ;jetzt bei A-E, bzw d0 gibt das genaue Ende an.

Optimize:
        sub.l   a5,a5                           ;Default für VBR ist 0
        moveq   #1+2+4+8+128,d7                 ;68010+68020+68030+68040+68060
        and     AttnFlags(a6),d7                ;Mit vorhandenen Prozessor-Flags maskieren
        beq.b   .NoTurbo                        ;Nur 68000
        movec   VBR,a5                          ;Vector Base Register holen
.NoTurbo:
        move.l  $24(a5),-(a7)                   ;Trace-Vector sichern
        move.l  a5,-(a7)                        ;VBR sichern
        lea     TraceWatcher(pc),a0             ;Trace-Überwachungs-Routine
        move.l  a0,$24(a5)                      ;In Trace-Vector eintragen
        lea     SplinePrg(pc),a2                ;Hier soll das erzeugte Programm abgelegt werden
        lea     -400(a7),a7                     ;Work-Space für die Spline-Routine
        lea     300(a7),a0                      ;Workspace absteigend
        lea     320(a7),a3                      ;Counter für Iterations-tiefe,
                                                ;wird nur für die normale/Trace-Version benötigt
        move    #3,(a3)                         ;Anfangs-Rekursions
                                                ;(Rekursions-Tiefe (Max 14=>1+2^(14+1)=32769 Pixel))
        move    #$a700,SR                       ;Alle Interrupts aus, aber TRACE an !
        bsr.s   FbRec                           ;Ab hier schlägt nach jedem Befehl die
                                                ;Trace-Exception zu, siehe -> TraceWatcher
        move    #$2700,SR                       ;Alle Interrupts aus, und kein TRACE mehr.
        subq    #2,a2                           ;Den obigen Befehl "move #$2700,SR" wieder wegnehmen.
        move    #$4e75,-2(a2)                   ;Erzeugte Routine mit rts abschliessen.
        lea     400(a7),a7                      ;Stack korrigieren
        move.l  (a7)+,a5                        ;VBR restaurieren
        move.l  (a7)+,$24(a5)                   ;Alten Trace-Vector setzen.
        rte                                     ;Ende des SuperVisor-Modus

;Diese Routine wird bei jedem ausgeführtem Befehl aufgerufen
;"Befehl überspringen" bedeutet nicht, das der Befehl nicht ausgeführt wird,
;er wird nur nicht in der erzeugten Routine übernommen.
TraceWatcher:
        move.l  2(a7),a1                        ;Gerade auszuführenden Befehl holen
        move    (a1),d7                         ;Momentaner Befehl
        cmp     #$5353,d7                       ;subq #1,(a3) == Iterationstiefe kleiner ?
        beq.b   .SkipCommand                    ;Befehl überspringen
        cmp     #$5253,d7                       ;addq #1,(a3) == Iterationstiefe größer ?
        beq.b   .SkipCommand                    ;Befehl überspringen
        cmp     #$4e75,d7                       ;rts ?
        beq.b   .SkipCommand                    ;Befehl überspringen
        clr.b   d7                              ;Untereres Byte löschen
        cmp     #$6400,d7                       ;bcc.b xxx
        beq.b   .SkipCommand                    ;Befehl überspringen
        cmp     #$6100,d7                       ;bsr.s xxx
        beq.b   .SkipCommand                    ;Befehl überspringen
        cmp     #$4c00,d7                       ;movem (ax)+
        beq.b   .TakeLong                       ;Langwort übernehmen
        cmp     #$4800,d7                       ;movem -(ax)
        beq.b   .TakeLong                       ;Langwort übernehmen
        move    (a1),(a2)+                      ;Wort übernehmen
.SkipCommand:
        rte                                     ;Zurück und Befehl ausführen !

.TakeLong:
        move.l  (a1),(a2)+                      ;Langwort übernehmen
        rte                                     ;Zurück und Befehl ausführen !

        ;Long-Align etc unnötig, da diese Routine nur 1 mal ausgeführt wird.

FbRec:  ;Dies ist die "normale" Spline-Routine, die optimiert werden soll.

.IterM: move    d5,d2
.IterL: add     d1,d2
        roxr    #1,d2
        addx    d0,d1
        roxr    #1,d1
        addx    d6,d5
        roxr    #1,d5
        move    d5,d4
        add     d2,d4
        roxr    #1,d4
        addx    d1,d2
        roxr    #1,d2
        move    d4,d3
        add     d2,d3
        roxr    #1,d3
        subq    #1,(a3)
        bcc.b   .ReIter
        sub     a2,d3
        sub     a2,d6
        movem   d3/d6,-(a0)
        addq    #1,(a3)
        rts

.ReIter:movem   d3/d4/d5/d6,-(a7)
        move    d2,d5
        move    d3,d6
        bsr.b   .IterL
        movem   (a7)+,d0/d1/d5/d6
        bsr.b   .IterM
        addq    #1,(a3)
        rts

;Der normale init-Code für die Spline-Routine
A:      movem   -6(a0),d0/d1/d5/d6
        add     a2,d0
        add     a2,d1
        add     a2,d5
        add     a2,d6

;An dieser Stelle wird die optimierte Routine abgelegt.
SplinePrg:      ds.l    147
E: