; Latticelib.a: Amiga shared runtime library shell for Lattice 'C' 5.02+
; By Rick Huebner, 28 October 1989.  Released to the Public Domain.
; Derived from sample.library.asm in ROM Kernal Reference Manual and other
; sources.

; Provides RomTag and other magic thingies needed to make a set of
; C routines into a library.  Should work with most any set of routines;
; just substitute in the proper external labels.  This file should be the
; first one given in the link list, so that the RomTag struct can be quickly
; & easily found by the system when the library is opened.

; 5.04 note: I just got done trying to use the new libent and libinit modules
; provided with Lattice C 5.04, and ran into a few problems.  I'm probably
; not using them quite right (the update docs are pretty sketchy), but I'm
; not going to waste any more time on them.  I'd already written and tested
; this stuff before 5.04 came, and it works well.  If it ain't broke...

        INCLUDE "exec/types.i"
        INCLUDE "exec/libraries.i"
        INCLUDE "exec/lists.i"
        INCLUDE "exec/initializers.i"
        INCLUDE "exec/resident.i"
        INCLUDE "xprlibver.i"

        ; Things we define for external reference (for easier debuggging)
        XDEF    LibStart
        XDEF    RomTag
        XDEF    LibName
        XDEF    LibIDString
        XDEF    LibInit
        XDEF    LibOpen
        XDEF    LibClose
        XDEF    LibExpunge
        XDEF    LibExtFunc
        XDEF    XProtocolCleanup
        XDEF    XProtocolSetup
        XDEF    XProtocolSend
        XDEF    XProtocolReceive
        XDEF    XProtocolHostMon
        XDEF    XProtocolUserMon
        XDEF    LibEnd

        ; Our library base structure description
        STRUCTURE XPRBase,LIB_SIZE
        ULONG   xb_SegList
        LABEL   XPRBase_SIZEOF


        SECTION text,code

        ; Things we need others to define
        XREF    @XProtocolCleanup
        XREF    @XProtocolSetup
        XREF    @XProtocolSend
        XREF    @XProtocolReceive
        XREF    @XProtocolHostMon
        XREF    @XProtocolUserMon
        XREF    __BSSBAS
        XREF    __BSSLEN
        XREF    _AbsExecBase
        XREF    _LVOOpenLibrary
        XREF    _LVOCloseLibrary
        XREF    _LVORemove
        XREF    _LVOFreeMem

  ; seems to be missing??
SysBase    ds.b 4

        ; Supposed start of executable code.  This is where execution
        ; will start if anybody's silly enough to try and run the library
        ; from the command line.  Just return the highest error code we
        ; conveniently can to tell them they screwed up.
LibStart:
        moveq   #$7F,d0
        rts

        ; Where the magic begins.  OpenLibrary actually looks through the
        ; library file contents trying to find this table by locating the
        ; magic RTC_MATCHWORD value followed by its own address.  This
        ; table then tells OpenLibrary where to find other things it needs.
        ; This needs to be close to the front of your library file to cut
        ; down on the amount of searching OpenLibrary does; that's why
        ; this object file should be first in the link list.
RomTag: dc.w    RTC_MATCHWORD   ; Magic value to search for to find table
        dc.l    RomTag          ; Address of matchword; the two together prevent accidental matches
        dc.l    LibEnd          ; Address of end of library handler code
        dc.b    RTF_AUTOINIT    ; Request system to automatically initialize our library
        dc.b    VERSION         ; Version number of our library (defined below)
        dc.b    NT_LIBRARY      ; Node type = Library
        dc.b    0               ; Node priority = 0 (normal)
        dc.l    LibName         ; Name of this library file, for debugging info
        dc.l    LibIDString     ; More debugging info
        dc.l    inittable       ; Initialization table used by RTF_AUTOINIT

;VERSION  EQU    0
;REVISION EQU    1
LibName:
        dc.b    "xprfts.library",0
LibIDString:
        dc.b    "Xpr for FTS-1/FTS-7 fidonet sessions (20 Sep 1992)",13,10,0

        ds.w    0

inittable:
        dc.l    XPRBase_SIZEOF  ; Size of our library base struct
        dc.l    functable       ; Where our function addresses are
        dc.l    datatable       ; Initialization info for our library base struct
        dc.l    LibInit         ; Library initialization routine address

functable:
        dc.l    LibOpen                 ; Addresses of all library functions
        dc.l    LibClose                ; First 4 MUST be provided, in this order
        dc.l    LibExpunge
        dc.l    LibExtFunc
        dc.l    XProtocolCleanup        ; The meat of the library.
        dc.l    XProtocolSetup
        dc.l    XProtocolSend
        dc.l    XProtocolReceive
        dc.l    XProtocolHostMon
        dc.l    XProtocolUserMon
        dc.l    -1

        ; Things for the system to automatically initialize for us via RTF_AUTOINIT request
datatable:
        INITBYTE        LN_TYPE,NT_LIBRARY
        INITLONG        LN_NAME,LibName
        INITBYTE        LIB_FLAGS,LIBF_SUMUSED | LIBF_CHANGED
        INITWORD        LIB_VERSION,VERSION
        INITWORD        LIB_REVISION,REVISION
        INITLONG        LIB_IDSTRING,LibIDString
        dc.l    0


        ; System interface routines.  Exec has performed Forbid() before
        ; getting here, so do this stuff quick and get the hell out.


        ; Routine which is executed by the system as part of first OpenLibrary
        ; call, when the library is first loaded into RAM from disk.
        ; D0 = library base pointer, A0 = segment list pointer.  Must return
        ; nonzero in D0 if initialization worked, or zero if it failed.
LibInit:
        move.l  d0,-(sp)                ; Save D0 for return code
        move.l  d0,a1                   ; A1 = library base
        move.l  a0,xb_SegList(a1)       ; Save seglist addr for future expunge
        lea     __BSSBAS,a0             ; Initialize BSS memory to 0s
        move.l  #__BSSLEN,d0
        moveq   #0,d1
        bra.s   clr_lp
clr_bss move.l  d1,(a0)+
clr_lp  dbf     d0,clr_bss
        move.l  (sp)+,d0                ; Return nonzero = success
        rts

        ; Open the library.  Executed by system as part of OpenLibrary call,
        ; after loading the library into RAM and calling LibInit if necessary.
        ; D0 = version, A6 = library base.  Return nonzero if open worked,
        ; or zero if open failed for some reason.
LibOpen:
        addq.w  #1,LIB_OPENCNT(a6)              ; Increment open count
        bclr    #LIBB_DELEXP,LIB_FLAGS(a6)      ; Clear delayed expunge flag
        move.l  a6,d0                           ; Return nonzero = success
        rts

        ; Close the library.  Executed by system as part of CloseLibrary call.
        ; A6 = library base.  Return seglist address if a delayed expunge
        ; was performed, else return 0 if library is still loaded.
LibClose:
        moveq   #0,d0                           ; Init return value = 0
        subq.w  #1,LIB_OPENCNT(a6)              ; Decrement open count
        bne.s   dontexpunge                     ; If still open by others, can't expunge
        btst    #LIBB_DELEXP,LIB_FLAGS(a6)      ; Was an expunge requested while we were open?
        beq.s   dontexpunge
        bsr.s   LibExpunge                      ; If so, do it now
dontexpunge:
        rts

        ; Expunge the library (remove it from RAM).  Executed by system
        ; memory allocation routine when memory gets tight.  A6 = library
        ; base.  Return seglist address if library was closed and we were
        ; able to expunge, else return 0 if library is still loaded.
LibExpunge:
        movem.l d2/a5/a6,-(sp)
        move.l  a6,a5
        move.l  _AbsExecBase,a6                 ; Get ExecBase for future use
        tst.w   LIB_OPENCNT(a5)                 ; Is library open?
        beq.s   doexpunge
        bset    #LIBB_DELEXP,LIB_FLAGS(a5)      ; If so, set delayed expunge flag
        moveq   #0,d0                           ; and return 0
        bra.s   expungedone
doexpunge:
        move.l  xb_SegList(a5),d2               ; Save seglist address in D2
        move.l  a5,a1                           ; A1 = library base address
        jsr     _LVORemove(a6)                  ; Unlink library node from system library list
        moveq   #0,d0                           ; Compute total size of library node
        move.w  LIB_NEGSIZE(a5),d0              ;   D0 = bytes used before base
        move.l  a5,a1
        sub.l   d0,a1                           ;   A1 = base - negsize
        add.w   LIB_POSSIZE(a5),d0              ;   D0 = possize + negsize
        jsr     _LVOFreeMem(a6)                 ; Free library node memory
        move.l  d2,d0                           ; Return segment list address
expungedone:
        movem.l (sp)+,d2/a5/a6
        rts

        ; "Extra" function (room for future growth?).  We don't need it,
        ; so dummy it out.
LibExtFunc:
        moveq   #0,d0
        rts



; Added glue to protect the comm program from having us munge its registers
; when it calls our code, due to bug which caused us to munge the A6
; register in an earlier version.  Since the XPR spec requires the arguments
; to be passed in the same registers that Lattice uses for function call
; register arguments, all we have to do is save the non-changeable registers
; on entry and restore them on exit.

XProtocolCleanup:
        movem.l d2-d7/a2-a6,-(sp)
        jsr     @XProtocolCleanup
        movem.l (sp)+,d2-d7/a2-a6
        rts

XProtocolSetup:
        movem.l d2-d7/a2-a6,-(sp)
        jsr     @XProtocolSetup
        movem.l (sp)+,d2-d7/a2-a6
        rts

XProtocolSend:
        movem.l d2-d7/a2-a6,-(sp)
        jsr     @XProtocolSend
        movem.l (sp)+,d2-d7/a2-a6
        rts

XProtocolReceive:
        movem.l d2-d7/a2-a6,-(sp)
        jsr     @XProtocolReceive
        movem.l (sp)+,d2-d7/a2-a6
        rts

XProtocolHostMon:
        movem.l d2-d7/a2-a6,-(sp)
        jsr     @XProtocolHostMon
        movem.l (sp)+,d2-d7/a2-a6
        rts

XProtocolUserMon:
        movem.l d2-d7/a2-a6,-(sp)
        jsr     @XProtocolUserMon
        movem.l (sp)+,d2-d7/a2-a6
        rts

LibEnd:
        END
