*** FME.asm - FastMemEmulator V1.0 - © 30.09.1989 by Holger Lubitz
***
*** Patcht die AllocMem()-Routine so, daß keine explizite Anforderung von
*** FastMem mehr möglich ist, wenn nicht gleichzeitig das MEMF_LARGEST-Bit
*** gesetzt ist. Bei bereits installiertem Patch wird dieser entfernt.
***
*** Sinn der Sache ist, an sich interessante Programme wie Evolution (Fish
*** 239) oder Crud, Demon und Life (alle Fish 249), die sich aber aus
*** unerfindlichen Gründen nicht ohne FastMem zufriedengeben, auch auf
*** Amigas ohne FastMem (512k oder 1MB mit Fatter Agnus) zum Laufen zu
*** bringen, ohne in den Programmen selbst herumpatchen zu müssen.
***
*** Von der Benutzung dieses Programms auf Amigas MIT FastMemory wird
*** vorsorglich abgeraten ! (Auch wenn es normalerweise nichts schaden
*** dürfte, aber sicher ist sicher)
***
*** Quellen: A68k von Fish 186, BLink von Fish 110, small.lib von Fish 92
***
*** 1> A68k FME.asm
*** 1> BLink FME.o small.lib to FME
***
*** FME ist zuerst im AmigaJUICE 17 (November 1989) erschienen.
*** Die jeweils neueste AmigaJUICE-Ausgabe gibts gegen Einsendung einer
*** Leerdiskette mit frankiertem Rückumschlag (1,70 DM Porto) bei:
*** AmigaJUICE, c/o Holger Lubitz, Postfach 1431, 3070 Nienburg/Weser
***
*** FME darf frei kopiert werden, wenn das Programm zusammen mit dem Source
*** und unverändert weiterkopiert wird. (diese Vermerke müssen drinbleiben !)
***
*** P.S.: 380 Bytes für dieses Programm sind ziemlich kurz, oder ?
***       An alle: Lernt Assembler, wenn ihr den Amiga WIRKLICH effizient
***       programmieren wollt !!

   XREF     _LVOAllocMem
   XREF     _LVOClose
   XREF     _LVOCloseLibrary
   XREF     _LVODelay
   XREF     _LVOForbid
   XREF     _LVOFindTask
   XREF     _LVOFreeMem
   XREF     _LVOGetMsg
   XREF     _LVOOldOpenLibrary
   XREF     _LVOOpen
   XREF     _LVOOutput
   XREF     _LVOPermit
   XREF     _LVOReplyMsg
   XREF     _LVOSetFunction
   XREF     _LVOWaitPort
   XREF     _LVOWrite

_AbsExecBase = 4
ThisTask     = 276
pr_CLI       = $ac
pr_MsgPort   = $5c
MODE_OLDFILE = 1005

   SECTION "",CODE

*** Registerbelegung: A6 reserviert für Exec-Base
***                   A5 reserviert für Adresse der Taskstruktur
***                   A4 reserviert für DOS-Base
***                   A3 reserviert für Adresse des Speicherblocks
***                   D7 reserviert für Länge des Speicherblocks
***                   D6 reserviert für Fenster-Handle

*** Eigenen Task finden

   move.l   _AbsExecBase,a6         ; Exec-Basisadresse
   move.l   ThisTask(a6),a5         ; FindTask(0) - Thanxx Fridtjof

*** DOS-Library öffnen

   lea      dosname(pc),a1          ; Zeiger auf 'dos.library'
   jsr      _LVOOldOpenLibrary(a6)  ; Version ist egal
   move.l   d0,a4                   ; Basisadresse in A4
                                    ; Kein Test !
                                    ; Ohne dos.library sind wir eh schon kurz
                                    ; vorm Absturz :-)
                                    ; Übrigens: DOS ist die EINZIGE Library,
                                    ; die ihre Basisadresse beim Aufruf NICHT
                                    ; in A6 braucht (BCPL's einziger Vorteil)

*** Test auf Workbench oder CLI

   tst.l    pr_CLI(a5)              ; Sind wir vom CLI aus gestartet worden ?
   beq.s    WB                      ; Wenn nicht dann zum WB-Startup

*** CLI-Startup

CLI
   jsr      _LVOOutput(a4)          ; Handle des CLI-Fensters
   move.l   d0,d6                   ; in D6
   bra.s    main                 ; und zum Start des Patches

*** WB-Startup

WB
   lea.l    pr_MsgPort(a5),a0       ; Sonst auf die Message warten
   jsr      _LVOWaitPort(a6)        ; die die Workbench sendet
   jsr      _LVOGetMsg(a6)          ; Sie ist da, wie schön !
   move.l   d0,-(a7)                ; Zeiger auf Message sichern
   lea      fenster(pc),a0          ; Zeiger auf Fenstertitel
   move.l   a0,d1                   ; in D1
   move.l   #MODE_OLDFILE,d2        ; CON: sollte es schon geben
   jsr      _LVOOpen(a4)            ; öffnen
   tst.l    d0                      ; hats geklappt ?
   beq.s    wbexit                  ; sonst hats keinen Zweck
   move.l   d0,d6                   ; Fenster-Handle in D6 sichern

main

*** Länge des Patches ermitteln und in D7 speichern

   moveq    #endpatch-startpatch,d7 ; Länge unseres Patches

*** Testen, ob wir schon installiert sind

   move.l   _LVOAllocMem+2(a6),a3   ; Anfangsadresse AllocMem()
   move.l   startpatch(pc),a0       ; Start unseres Patches
   cmp.l    (a3),a0                 ; sind wir schon da ?
   beq.s    remove                  ; dann entfernen

*** Speicher für den Patch reservieren

   move.l   d7,d0                   ; Länge in D0
   moveq    #0,d1                   ; keine besonderen Anforderungen
   jsr      _LVOAllocMem(a6)        ; Speicher belegen

*** Speicher bekommen ?

   tst.l    d0                      ; Enthält D0 eine Startadresse ?
   beq.s    fehler                  ; bei 0 haben wir keinen Speicher bekommen
                                    ; TEST! Speicheranforderungen müssen
                                    ; immer getestet werden, auch wenn das
                                    ; System lumpige 16 Bytes eigentlich
                                    ; finden sollte.

*** Startadresse in A3 zwischenspeichern

   move.l   d0,a3                   ; Adressen immer in Adressregister !
                                    ; außerdem brauchen wirs noch als Basis
                                    ; (schau mal ein paar Zeilen tiefer)

*** Den Patch kopieren

   lea      startpatch(pc),a0       ; Startadresse des Patches in A0
   move.l   a3,a1                   ; Start reservierter Speicher in A1
   subq     #1,d7                   ; weil DBRA-Loop
copyloop                            ; Kopierschleife
   move.b   (a0)+,(a1)+             ; byteweise kopieren
   dbra     d7,copyloop             ; weil in D7 die Länge in Bytes steht

*** Korrekten ROM-Einsprung für AllocMem in Patch nachtragen

   move.l   _LVOAllocMem+2(a6),allocmem-startpatch+2(a3)

*** AllocMem() umpatchen

   move.l   a3,d0                   ; Startadresse des Patches
   bsr.s    patch

*** Installed-Text ausgeben

   lea      text1(pc),a0            ; Text-Adresse nach A0
   moveq    #text1e-text1,d3        ; Länge in D3
   bsr.s    schreibe

*** und aufräumen

   bra.s    cleanup

*** Hier wird der Patch wieder entfernt

remove
   move.l   allocmem-startpatch+2(a3),d0 ; originalen AllocMem-Einsprung holen
   bsr.s    patch

*** und der Speicher wieder freigegeben

   move.l   d7,d0                   ; Länge in D0
   move.l   a3,a1                   ; Startadresse in A1
   jsr      _LVOFreeMem(a6)         ; D0 Bytes ab A1 freigeben

*** Removed-Text ausgeben

   lea      text2(pc),a0
   moveq    #text2e-text2,d3
   bsr.s    schreibe
   bra.s    cleanup

*** Fehler-Text ausgeben

fehler
   lea      text3(pc),a0
   moveq    #text3e-text3,d3
   bsr.s    schreibe

*** Falls vom CLI gestartet, sind wir fast fertig

cleanup
   tst.l    pr_CLI(a5)              ; war es das CLI ?
   bne.s    closelib                ; dann dos.library schließen

*** Sonst haben wir noch ein bißchen zu tun (WB-Cleanup)

*** Fenster schließen

   move.l   #150,d1                 ; 150/50 (also 3) Sekunden
   jsr      _LVODelay(a4)           ; warten (damit mans auch lesen kann)
   move.l   d6,d1                   ; Fenster
   jsr      _LVOClose(a4)           ; schließen
wbexit
   bsr.s    closelib                ; dos-lib schließen

*** Msg beantworten

   jsr      _LVOForbid(a6)          ; Wir wollen nicht zu früh von der WB
                                    ; rausgeschmissen werden
   move.l   (a7)+,a1                ; Die gesicherte msg nach A1
   jmp      _LVOReplyMsg(a6)        ; und endlich antworten

*** DOS-Lib schließen (erwartet DOSBase in A4 und Exec-Base in A6)

closelib
   move.l   a4,a1                   ; Dos-Base nach A1
   jmp      _LVOCloseLibrary(a6)    ; schließen

*** Die Routine zum Patchen von AllocMem() in der Exec-Sprungleiste
*** wird zweifach aufgerufen, steht darum hier.

patch
   jsr      _LVOForbid(a6)          ; Multitasking aus (sicher ist sicher)
   move.l   #_LVOAllocMem,a0        ; Offset von AllocMem
   move.l   a6,a1                   ; gepatcht wird in Exec
   jsr      _LVOSetFunction(a6)     ; und ändern.
   jmp      _LVOPermit(a6)          ; Multitasking wieder erlauben

*** Text ausgeben (a0 und d3 müssen Adresse und Länge enthalten)

schreibe
   move.l   d6,d1
   move.l   a0,d2
   jmp      _LVOWrite(a4)

*** Hier beginnt der eigentliche Patch

startpatch            ; Label für Patch-Startadresse
   btst     #17,d1    ; MEMF_LARGEST-Bit testen
   bne.s    allocmem  ; Bei soviel Hunger MEMF_FAST lieber nicht löschen
                      ; (für Kompatibilität mit etlichen NOFASTMEM-Programmen)
   bclr     #2,d1     ; sonst MEMF_FAST-Bit löschen
allocmem
   jmp      $12345678 ; diese Adresse wird erst in der Patch-Kopie angepaßt
                      ; (sonst wäre FME nicht resident-fähig)
endpatch              ; dient zur Längenermittlung des Patches

*** Dies ist die Text-Sektion

dosname
   dc.b     "dos.library",0
fenster
   dc.b     "CON:10/10/320/80/HAL's FastMemEmulator",0

text1
   dc.b     "Patch installiert",10
text1e

text2
   dc.b     "Patch entfernt",10
text2e

text3
   dc.b     "Kein Speicher",10
text3e

   END
