
                     *****************************
                     HeliOS LIMITER motor routines
                     *****************************

************
Introduction
************

The HeliOS LIMITER routines are part of the interrupt-driven game operating
system and function as one of the HeliOS "motor" routines.

These are fast optimised machine coded routines which can be controlled
entirely by pre-defined data structures.

These functions only work in HeliOS mode.

HeliOS LIMITER functions allow fast and efficient performance of simple
numeric value limiting synchronously with other functions performed by the
interrupt driven HeliOS system.

LIMITERs are designed to allow preset memory locations to have their
contents constrained automatically between specified limits.

These LIMITER functions allow interactions between data structures to be 
set up which will run fully automatically in the background.

Using pre-defined control data structures, along with direct programmability
if required, you can generate a number of different limiting functions.

These routines have many applications, in particular they allow mutual
control between events occurring in different sub-systems.

It is impossible to list all the possible ways of using these highly
flexible routines, and it will be easier to see the potential of this
system after examining how it works.

It is worth pointing out that all HeliOS motor functions are not only
pre-programmable, but they operate in a mutually self-programming way by
allowing "modifiers" and "results" to operate on other motors.  In other
words input and output from motor programs do not only work with parameters 
stored in their own "private" data structures: motors can also read inputs
and distribute results by interacting with control data structure fields
of other motors or any other computed objects.

This INDIRECTION of input and output, a feature common to ALL HeliOS
data objects, allows complex interlinking and self-programmability.

The mutual self-programmability of HeliOS objects means that the results
of one operation can be used to automatically program another, which in
turn can (re)act on the first....and so on.

All this can be set up to work automatically without you having to do any
intermediate programming to manage all the interactions.

This means, in other words, that all HeliOS motors can PROGRAM EACH OTHER,
so input or output data can be modified by other motor functions and can
in turn program other motors.

This mutual programmability combined with the BEFORE and AFTER functions
give the HeliOS motor functions considerable power from ultra fast and very
simple routines.

******
Timing
******

It is an important consideration that all motor functions are fully
synchronised with all other HeliOS internally automated functions and
with the display frame rate.

Motors are run in the order in which they are installed: you must remember
this if you are using one motor function to modify another.

******************
Control structures
******************

The main LIMITER control structure is as follows:

-------------------------
LIMITER control structure
-------------------------

Limiter_BeforeForth(w) = HeliOS CFA to run BEFORE each Limiter calculation
Limiter_BeforeCode(l)  = Machine code to run BEFORE each Limiter calculation
Limiter_AfterForth(w)  = HeliOS CFA to run AFTER each Limiter calculation
Limiter_AfterCode(l)   = Machine code to run AFTER each Limiter calculation
Limiter_Flags(w)       = Control flags word ( See below)
Limiter_CountDown(w)   = Countdown time (If non-zero sets countdown)
Limiter_CDFlags(w)     = Countdown flags word (-> "Flags" at CountDown time)
Limiter_CDForth(w)     = Countdown HeliOS function CFA (optional)
Limiter_CDCode(l)      = Countdown machine code function pointer (optional)
Limiter_SkipTimer(w)   = Limiter skip internal timer register
Limiter_SkipCount(w)   = Limiter skip count = How many "ticks" to skip (0=Do all)
Limiter_ID(w)          = Motor handler ID = 3 for Limiter
Limiter_Count(w)       = Number of Limiter data blocks
Limiter_Data(l)        = Limiter data list pointer
Limiter_UserDataPtr(l) = Free user data pointer
Limiter_UserData1(w)   = Free user data1
Limiter_UserData2(w)   = Free user data2
Limiter_UserData3(w)   = Free user data3
Limiter_UserData4(w)   = Free user data4
Limiter_UserData5(w)   = Free user data5
Limiter_UserData6(w)   = Free user data6
Limiter_UserStatus(w)  = Free user status

Here is an amplified description of each field:

Limiter_BeforeForth This field, if non-null, contains the CFA af a HeliOS
                    command which will be run BEFORE each iteration of the
                    Limiter function.

                    A 32-bit pointer to the Limiter control structure will
                    be placed on the stack when the HeliOS BEFORE command
                    is called, so you must take care to clear the stack.

Limiter_BeforeCode  This field, if non-null, contains a pointer to a machine
                    code routine which will be run BEFORE each iteration of
                    the Limiter function.

                    A 32-bit pointer to the Limiter control structure will
                    be placed in address register A0 when the BEFORE
                    command code is called.

Limiter_AfterForth  This field, if non-null, contains the CFA af a HeliOS
                    command which will be run AFTER each iteration of the
                    Limiter function.

                    A 32-bit pointer to the Limiter control structure will
                    be placed on the stack when the HeliOS AFTER command
                    is called, so you must take care to clear the stack.

Limiter_AfterCode   This field, if non-null, contains a pointer to a machine
                    code routine which will be run AFTER each iteration of
                    the Limiter function.

                    A 32-bit pointer to the Limiter control structure will
                    be placed in address register A0 when the AFTER command
                    code is called.

Limiter_Flags       This field contains the Limiter function control flags.

                    The following function control flags are available:

                    -3  = SelfRemove at once
                    0   = Skip Limiter function

                    "Before" functions still run in "Skip" mode.

Limiter_CountDown   Sets up a CountDown, so that after the number of "ticks"
                    specified in this field the CDFlags value will be stored
                    into the Flags field of the Limiter command structure.

                    This function is switched off after each CountDown.

Limiter_CDFlags     If a CountDown is being done, the value in this field
                    will be placed in the "Flags" field of the Limiter
                    command structure when the CountDown is complete.

Limiter_CDForth     This field contains either null or the CFA of a HeliOS
                    function which you wish to be executed after CountDown
                    has completed.

Limiter_CDCode      This field contains either null or a pointer to a machine
                    code routine which you wish to be executed after the
                    CountDown has completed.

Limiter_SkipTimer   This field is used to store the internal timer status
                    of the Limiter motor.

Limiter_SkipCount   This value gives the time delay between each iteration
                    of the Limiter function.  The Limiter will skip however
                    many "ticks" are specified here between each active
                    cycle.

                    A SkipCount value of "0" gives full speed operation.

Limiter_ID          This MUST be set to "5", to identify the Limiter function.

Limiter_Count       The number of data items constituting this Limiter.

Limiter_Data        A pointer to the start of the sequence of Limiter data
                    structures associated with this control structure, as
                    defined below, each placed one after the other.

                    Each master Limiter control structure can drive an
                    unlimited number of individual LimiterS, each of which
                    has a different data structure.

Limiter_UserDataPtr This is a "free" field which you can use as you wish.
Limiter_UserData1   This is a "free" field which you can use as you wish.
Limiter_UserData2   This is a "free" field which you can use as you wish.
Limiter_UserData3   This is a "free" field which you can use as you wish.
Limiter_UserData4   This is a "free" field which you can use as you wish.
Limiter_UserData5   This is a "free" field which you can use as you wish.
Limiter_UserData6   This is a "free" field which you can use as you wish.
Limiter_UserStatus  This is a "free" field which you can use as you wish.


--------------------
LimiterData structure
--------------------

LimiterData_Source1(l)   = Pointer to first source address
LimiterData_LowValPtr(l) = Pointer to second source address
LimiterData_HiValPtr(l)  = Pointer to target address
LimiterData_Length(w)    = Data length of operation
LimiterData_Sign(w)      = Modifier

Here is an amplified description of each field:

LimiterData_Source1(l)  This field contains a pointer to the memory address
                        to which the limiting function is to be applied.

LimiterData_LowValPtr(l) This field contains a pointer to a memory address
                         containing the LOW limiting value.


LimiterData_HiValPtr(l) This field contains a pointer to a memory address
                        containing the HIGH limiting value.

LimiterData_Length(w)   This field specifies whether this operation is on
                        1, 2, or 4 byte values and should be set accordingly
                        to "1", "2", or "4".

LimiterData_Sign(w)     This field specifies whether the Limiter will use
                        signed or unsigned arithmetic, as folllows:

                        Sign 1  -> Signed
                        Sign 0  -> Unsigned


***********************************
HeliOS Limiter control command words
***********************************

There are NO words specifically to control Limiter functions.

All control is via the data structures detailed above.

Limiters are started by using the expression:

  MyLimiter INSTALLMOTOR

Limiters are stopped by using the expression:

  MyLimiter REMOVEMOTOR


**************
Using Limiters
**************

Limiters are VERY easy to use and to set up.

First you need to allocate a master Limiter structure:

    Limiter_SIZEOF MAKESTRUCTURE  MyLimiter D!

or something similar......

Then you need to allocate at least one Limiter data structure:

    LimiterData_SIZEOF MAKESTRUCTURE MyLimiterData D!

Then you must set up the pointers and data structure values:

    MyLimiterData D@  MyLimiter D@ Limiter_Data INDEXD!L

    MyLimiter D@ SETSTRUCTURE1

    1    Limiter_Count     STRUCTURE1  !L
    1    Limiter_Flags     STRUCTURE1  !L
    1    Limiter_SkipCount STRUCTURE1  !L
    5    Limiter_ID        STRUCTURE1  !L

 \  Set up Limiter to limit Source1 between -12 and +12 (16-bit).


    0    VARIABLEL Source1
    -12  VARIABLEL LowLimit
    12   VARIABLEL HiLimit

    MyLimiterData D@ SETSTRUCTURE1

    Source1  LimiterData_Source1   STRUCTURE1 D!L
    LowLimit LimiterData_LowValPtr STRUCTURE1 D!L
    HiLimit  LimiterData_HiValPtr  STRUCTURE1 D!L
    2        LimiterData_Length    STRUCTURE1 !L
    1        LimiterData_Sign      STRUCTURE1 !L

Then you must use INSTALLMOTOR when you want to start the Limiter process:

    MyLimiter D@ INSTALLMOTOR

...and REMOVEMOTOR when you want to stop the Limiter process:

    MyLimiter D@ REMOVEMOTOR

*********************************************************************
End
*********************************************************************
