home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 277.lha / PatternLibrary / fdCompile / fdCompile.txt < prev    next >
Encoding:
Text File  |  1989-08-08  |  15.3 KB  |  378 lines

  1.                 fdCompile
  2.  
  3.  
  4. BackGround on AmigaDOS Shareable Libraries
  5.  
  6.     'fd' files are the files that Commodore and others supply which
  7.     describe routines in AmigaDOS shareable libraries and how to call them.
  8.     As an example, here is the 'fd' file for the 'translator.library':
  9.  
  10. ##base _TranslatorBase
  11. ##bias 30
  12. ##public
  13. Translate(inputString,inputLength,outputBuffer,bufferSize)(A0,D0/A1,D1)
  14. ##end
  15.  
  16.     The 'translator' library has only one routine, 'Translate', in it. This
  17.     file says that:
  18.  
  19.     - interface stubs should use the external symbol '_TranslatorBase'
  20.         to save the address of the library when it is loaded
  21.     - the first jump vector of the library starts at offset 30 in the
  22.         negative part of the library structure (thus at offset -30 from
  23.         the pointer stored in '_TranslatorBase')
  24.     - routine 'Translate' has 4 parameters, which should be passed in
  25.         registers A0, D0, A1 and D1. The symbolic names given are not
  26.         important, but do provide a human reader with some help in
  27.         knowing which is which.
  28.  
  29.     Thus, to use the 'Translate' routine (which translates ASCII strings of
  30.     English text into phoneme sequences which the narrator.device can
  31.     pronounce), a programmer must do the following:
  32.  
  33.     1) call the Exec routine 'OpenLibrary', passing it the name of the
  34.         library ("translator.library"), along with a version number
  35.         (often just 0). Exec will check to see if the library is
  36.         already loaded. If it isn't, it will try to LoadSeg from file
  37.         "LIBS:translator.library". After the load, Exec will call the
  38.         library's initialization routine which will set up a Library
  39.         structure which Exec can add to its list of loaded libraries.
  40.         The 'OpenLibrary' call will return the address of the Library
  41.         structure. Note that this pointer is actually into the middle
  42.         of the structure - at negative offsets are 6-byte entries, one
  43.         for each routine in the library, which are typically an
  44.         absolute JMP to the loaded routine.
  45.     2) Store the returned pointer into "_TranslatorBase"
  46.     then, on each call to 'Translate':
  47.     3) Set up the parameter registers:
  48.         A0 - address of ASCII string
  49.         D0 - length of ASCII string
  50.         A1 - address of buffer for phoneme sequence
  51.         D1 - length of buffer for phoneme sequence
  52.     4) Load the Library address (from "_TransalatorBase") into A6
  53.     5) JSR -30(A6)
  54.  
  55.     This is all well and good for an assembler programmer, but what about
  56.     those using high-level languages? The simple approach is to write an
  57.     interface routine, which takes parameters from where-ever the high-
  58.     level language puts them on a call (typically the stack), moves them to
  59.     the required register, loads the library base into A6, and does a branch
  60.     to the proper offset from that base. The latest Lattice C compiler is
  61.     able to generate the correct code directly, based on special directives
  62.     given to the compiler. Ignoring that technique, a C programer does the
  63.     following to call the routine:
  64.  
  65.     1) call 'OpenLibrary' (which is itself a stub, since it lives in
  66.         exec.library) with the proper parameters
  67.     2) store the resulting library address in the extern symbol
  68.         "TranslatorBase" (C usually adds the leading '_'). NOTE: I am
  69.         ignoring the case of the 'OpenLibrary' call failing.
  70.     then, on each call to 'Translate':
  71.     3) call 'Translate' with the appropriate parameters
  72.     then, when done with the library:
  73.     4) call 'CloseLibrary(TranslatorBase)' when done with the library.
  74.  
  75.     Step 3 will actually call the stub routine '_Translate' which copies
  76.     the parameters from the stack into the proper registers, loads the
  77.     Library pointer from '_TranslatorBase', and does the JMP through it.
  78.     Since the compiler uses register A6 internally, the stub routine should
  79.     save and restore it.
  80.  
  81.     In Draco, I did things a little bit differently:
  82.  
  83.     - the compiler doesn't stick on a '_', so the stub routine names
  84.         don't have one (the base name does, for consistency if someone
  85.         links C and Draco stuff together)
  86.     - the calling convention requires the subroutine to remove the
  87.         parameters from the stack, so the stubs must do that
  88.     - I kept the library base private to the stub routines, so for each
  89.         library there is an e.g. 'OpenTranslatorLibrary' and an e.g.
  90.         'CloseTranslatorLibrary'. The first is given only the version
  91.         number and the second has no argument. The first returns the
  92.         Library address in case the program needs it for some other
  93.         reason.
  94.  
  95.     Thus, the Draco sequence is:
  96.  
  97.     1) call 'OpenTranslatorLibrary' with the version number
  98.     ...
  99.     2) call 'Translate' as needed
  100.     ...
  101.     3) call 'CloseTranslatorLibrary'
  102.  
  103.     There are lots of libraries on the Amiga, and more keep coming, since
  104.     programmers can write more. There are LOTS of routines. Being lazy and
  105.     a compiler-writer to boot, I couldn't stand the idea of writing all of
  106.     those interface stubs in assembler. Thus, when I first ported Draco to
  107.     the Amiga, I wrote a program (then called 'convfd') which read in an
  108.     'fd' file, parsed it, and produced an object file containing all of the
  109.     needed interface stubs. fdCompile is the direct descendant of that
  110.     program, which was the first serious one I compiled with the Amiga
  111.     Draco compiler. fdCompile has grown a lot since then. With this as
  112.     introduction, here follows a description of fdCompile.
  113.  
  114.  
  115. fdCompile
  116.  
  117.     The usage line for fdCompile says:
  118.  
  119.     Use is: fdCompile -lLosSd fdfile ... fdfile
  120.  
  121.     This means that it takes one or more flags and one or more filenames,
  122.     which are expected to name 'fd' files. Each such file is processed
  123.     independently. In the following discussion, assume that fdCompile was
  124.     invoked with "fdcompile -lLosSd test_lib.fd". Also, assume that file
  125.     'test_lib.fd' contains:
  126.  
  127.     ##base _TestBase
  128.     ##bias 30
  129.     ##public
  130.     DoThing(p)(a0)
  131.     DoOtherThing(p,inputPtr,inputLen,output)(a0,a1,d0,d1)
  132.     ##end
  133.  
  134.     The flags, in detail, are:
  135.  
  136.     -l - produce an interface stub file for Draco. This is an unlinked
  137.     AmigaDOS object file which contains interface stubs which let a
  138.     Draco program open the library and call its routines. In our
  139.     example usage, the created file would be called 'test.o' (fdCompile
  140.     looks for the '_lib.fd' in the given file names.) It would contain
  141.     the equivalent of the following assembler code:
  142.  
  143.         _TestBase
  144.             ds.b       4
  145.         OpenTestLibrary
  146.             movea.l    (sp)+,a1
  147.             move.l     (sp)+,d0
  148.             move.l     a1,-(sp)
  149.             lea        L0020,a1
  150.             move.l     a6,-(sp)
  151.             movea.l    0x00000004,a6
  152.             jsr        -552(a6)
  153.             movea.l    (sp)+,a6
  154.             move.l     d0,_TestBase
  155.             rts 
  156.         L0020   dc.b       'test.library'
  157.             dc.b       0
  158.         CloseTestLibrary
  159.             movea.l    _TestBase,a1
  160.             move.l     a6,-(sp)
  161.             movea.l    0x00000004,a6
  162.             jsr        -414(a6)
  163.             movea.l    (sp)+,a6
  164.             rts 
  165.         DoThing
  166.             move.l     a6,-(sp)
  167.             movea.l    8(sp),a0
  168.             movea.l    _TestBase,a6
  169.             jsr        -30(a6)
  170.             movea.l    (sp)+,a6
  171.             movea.l    (sp)+,a1
  172.             addq.l     #4,sp
  173.             jmp        (a1)
  174.         DoOtherThing
  175.             move.l     a6,-(sp)
  176.             movea.l    20(sp),a0
  177.             movea.l    16(sp),a1
  178.             move.l     12(sp),d0
  179.             move.l     8(sp),d1
  180.             movea.l    _TestBase,a6
  181.             jsr        -36(a6)
  182.             movea.l    (sp)+,a6
  183.             movea.l    (sp)+,a1
  184.             adda.w     #16,sp
  185.             jmp        (a1)
  186.  
  187.     'OpenTestLibrary' calls 'OpenLibrary' in Exec, passing the string
  188.     "test.library" and the version number given by the user. The
  189.     returned library pointer is stored into '_TestBase' and returned.
  190.     'CloseTestLibrary' calls 'CloseLibrary' in Exec, passing the
  191.     contents of '_TestBase'. Both of the calls to Exec are done
  192.     directly, using the pointer to the Exec library which the system
  193.     stores in location 4. The two interface stubs do the required
  194.     copying of parameters and saving/restoring of registers. This was
  195.     the original purpose behind fdCompile, but is of use only for
  196.     people who use Draco. Changing fdCompile to work with some other
  197.     compiler is not hard, so those who want to do that can contact me
  198.     and I'll send them the source to fdCompile. If I get enough
  199.     requests, I can send it to 'comp.source.amiga' and/or CompuServe,
  200.     but I don't think that will be needed.
  201.  
  202.     -L - print the library entries and their offsets from the library base
  203.     pointer. This is of marginal use, but does supply the proper
  204.     offsets to those who want to do it by hand. The output for our
  205.     example library is:
  206.  
  207.         DoThing @ -30
  208.         DoOtherThing @ -36
  209.  
  210.     -o - produce a file which defines 'LVO_' symbols for the library
  211.     routine offsets from the library pointer. 'LVO' stands for Library
  212.     Vector Offset (or some such!). The file produced has an unnamed
  213.     HUNK_UNIT followed by a HUNK_EXT which contains EXT_ABS definitions
  214.     for the symbol offsets. In our example case, the file would be
  215.     called 'LVO_test.o' and, dumped, contains:
  216.  
  217.         hunk_ext:
  218.         LVO_DoThing: ext_abs: ffffffe2
  219.         LVO_DoOtherThing: ext_abs: ffffffdc
  220.  
  221.     This file can be linked in with the other object files of a program
  222.     in order to define, as external symbols, the offsets, which are
  223.     needed in order to call the Exec routine 'SetFunction'.
  224.  
  225.     -s - produce a file which has definitions for the loaded, absolute
  226.     addresses of the routines in the library. This is only useful with
  227.     libraries that are always at fixed addresses, i.e. are in the ROM,
  228.     or with some types of debugging. The addresses are found by
  229.     actually opening the library and peeking at the real vector. Again,
  230.     the file, in our example, would be called 'test_sym.o' and would
  231.     contain:
  232.  
  233.         hunk_ext:
  234.         #DoThing: ext_abs: 00296c20
  235.         #DoOtherThing: ext_abs: 00296d00
  236.  
  237.     The actual addresses would of course be different. Note that the
  238.     symbols defined all have a '#' on the front. This is to distinguish
  239.     them from the interface stub routines. My intended use for this
  240.     type of file is to read them into a debugger I am writing, so that
  241.     it can do at least partially symbolic disassembly of the ROM code.
  242.  
  243.     -S - this is related - it simple prints the information that '-s' puts
  244.     into the file. Output for our example:
  245.  
  246.         Compile @ 00296c20
  247.         Match @ 00296d00
  248.  
  249.     -d - this flag produces a disk-resident-library header file. The
  250.     AmigaDOS shareable libraries that live in LIBS: are said to be
  251.     disk-resident since they are not in the ROMs and therefore must be
  252.     loaded from disk when they are needed. Such files have a very
  253.     special format, which allows AmigaDOS and Exec to load them and add
  254.     them to the system's list of loaded libraries. I plan on writing a
  255.     lot of such libraries, so I wanted an automatic way of producing
  256.     them. I won't describe in detail what is required, but instead
  257.     refer the interested reader to the appropriate sections in the ROM
  258.     Kernel Manual. For our example, we would get a file called
  259.     'test_head.o', which contains (in case you are wondering, all of my
  260.     pretty disassemblies and object file dumps are done by my snazzy
  261.     new disassembler/dumper, 'Dis', which I should be sending out a
  262.     couple of days after this goes out):
  263.  
  264.         L0000   dc.w       0x4afc       ; RTC_MATCHWORD
  265.             dc.l       L0000
  266.             dc.l       L001a
  267.             dc.b       128
  268.             dc.b       1
  269.             dc.b       9
  270.             dc.b       0
  271.             dc.l       L00d8
  272.             dc.l       L00e5
  273.             dc.l       L001c
  274.         L001a   dc.b       0,0
  275.         L001c   dc.l       38       ; positive library size
  276.             dc.l       L00bc
  277.             dc.l       L002c
  278.             dc.l       L0048
  279.         L002c   dc.b       160,8,9,0,128,10
  280.             dc.l       L00d8
  281.             dc.b       160,14,6,0,144,20,0,1,128,24
  282.             dc.l       L00e5
  283.             dc.b       0,0,0,0
  284.         L0048   move.l     a1,-(sp)
  285.             movea.l    d0,a1
  286.             move.l     a0,34(a1)
  287.             movea.l    (sp)+,a1
  288.             rts 
  289.         L0054   addq.w     #1,32(a6)
  290.             bclr.b     #0x0003,14(a6)
  291.             move.l     a6,d0
  292.             rts 
  293.         L0062   clr.l      d0
  294.             subq.w     #1,32(a6)
  295.             bne        L0074
  296.             btst.b     #0x0003,14(a6)
  297.             beq        L0074
  298.             bsr        L0076
  299.         L0074   rts 
  300.         L0076   movem.l    <a1/a5/a6>,-(sp)
  301.             clr.l      d0
  302.             movea.l    a6,a5
  303.             tst.w      32(a5)
  304.             beq        L008c
  305.             bset.b     #0x0003,14(a5)
  306.             bra        L00b2
  307.         L008c   movea.l    a5,a1
  308.             movea.l    0x00000004,a6
  309.             jsr        -252(a6)
  310.             movea.l    a5,a1
  311.             move.w     16(a5),d0
  312.             suba.w     d0,a1
  313.             add.w      18(a5),d0
  314.             movea.l    0x00000004,a6
  315.             jsr        -210(a6)
  316.             move.l     34(a5),d0
  317.         L00b2   movem.l    (sp)+,<a6/a5/a1>
  318.             rts 
  319.         L00b8   clr.l      d0
  320.             rts 
  321.         L00bc   dc.l       L0054
  322.             dc.l       L0062
  323.             dc.l       L0076
  324.             dc.l       L00b8
  325.             dc.l       L0000
  326.             dc.l       L0000
  327.             dc.l       -1
  328.         L00d8   dc.b       'test.library'
  329.             dc.b       0
  330.         L00e5   dc.b       'test 1.0 ( 3 Aug 1989)'
  331.             dc.b       13,10,0,0,0
  332.  
  333.     This code includes the library header tables and data, along with
  334.     the required open, close, expunge and null routines. To use this
  335.     file to create a complete disk-resident library, it must be linked
  336.     with object files containing the actual library routines. Any
  337.     compiler-specific startup code should NOT be included. Anyone
  338.     intending to write such a library should be sure to understand
  339.     their nature fully - there are many restrictions on what features
  340.     of the language and its standard libraries that can be used.
  341.  
  342.     Note that, in order to be compatible with the interface stubs
  343.     generated by the '-l' option, the actual library routines must take
  344.     their parameters from the registers specified in the 'fd' file.
  345.     Also, since the interface stubs save and restore register A6,
  346.     specifying no parameters in the 'fd' file will NOT let you just
  347.     pass the required parameters on the stack. To be compatible with
  348.     the standard set by the existing shareable libraries, all
  349.     parameters should be passed in registers. Writing the library
  350.     routines in a high-level language can be done if that language
  351.     provides facilities to get at the registers on function entry. In
  352.     Draco, this is done with the 'code' construct. Lattice C can, I
  353.     believe, do it with the proper pragmas and declarations. Aztec C
  354.     can do it with #asm statements.
  355.  
  356.     Accompanying fdCompile in this package is an implementation of the
  357.     AmigaDOS pattern matcher as a general-purpose shareable library.
  358.     Although it is written in Draco, since it uses the standard
  359.     register interface, it can be called from any language. It serves
  360.     mostly as an example of a complete library. The header of the
  361.     actual library and the Draco interface stubs, were produced by
  362.     fdCompile from the included 'fd' file.
  363.  
  364.     AmigaDOS devices are a lot like AmigaDOS libraries - they share the
  365.     same header structure and can be loaded from DEVS: just like libraries
  366.     can be loaded from LIBS:. Some devices, such as 'timer.device' and
  367.     'console.device' contain useful routines, just like libraries do.
  368.     fdCompile can handle devices as well as libraries with the '-l' flag.
  369.     If the specified offset is 42 instead of 30, it will assume it is
  370.     dealing with a device. It will then produce a 'SetXXXDevice' routine
  371.     instead of the 'OpenXXXLibrary' and 'CloseXXXLibrary' routines. In
  372.     order to use the routines in the device, the programmer must pass the
  373.     address of the device structure (returned by 'OpenDevice') to the
  374.     'SetXXXDevice' routine, so that it is available to the stubs for the
  375.     device's routines. Again, consult the RKM for details. I haven't added
  376.     the ability to deal with devices to the '-s' or '-d' code, but if
  377.     someone needs it, let me know.
  378.