;
;$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 jetzt bei A-E,
        rts                                     ;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:

