# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : mos_mri
# Module type   : Makefile system
# Compiler(s)   : ANSI C
# Environment(s): MOS
#
# Description:
#       MRI 68k/CF toolset for MOS
#       This file provides Toolset initialisation and plugin functions
#       to makelib.pl2
#
# Contents:     MRI 68k/CF rules as used for the MOS
#
#............................................................................#

use strict;
use warnings;

#
#   Toolset Global variables
#
my $Toolset_DebugCode;
my $Toolset_DebugData;
my $Toolset_Product = '';
my $Toolset_Production_Only;

my $globName = 'glob$(GBE_TYPE)';               # Name of the MOS global library file

##############################################################################
#   ToolsetInit()
#       Runtime initialisation
#
##############################################################################

ToolsetInit();

sub ToolsetInit
{
    my( $version, $flavour );
    my $no_defines;
    my( @defines );
    my $board = '';

#.. Parse Toolset arguments
#
    Debug( "mos_mri(@::ScmToolsetArgs)\n" );

    $version = 0;                               # Default (not great)
    $flavour = '68k';
    foreach $_ ( @::ScmToolsetArgs ) {
        if (/^--Version=(.*)/) {                # Compiler version
            $version = "$1";
        } elsif (/^--68k/) {                    # Compiler flavour
            $flavour = '68k';
        } elsif (/^--coldfire/) {               # Compiler flavour
            $flavour = 'cf';
        } elsif (/^--NoDefines/) {               # Vanila defines
            $no_defines = 1;
        } else {
            Message( "mos_mri: unknown toolset argument $_ -- ignored" );
        }
    }

#.. Parse Platform Arguments
#
    foreach $_ ( @::ScmPlatformArgs ) {
        if (/^--product=(.*)/) {                # GBE product
            $Toolset_Product = $1;
        } elsif (/^--board=(.*)/) {             # Board subtypes
            $board = $1;
        } else {
            Message( "mos_mri: unknown platform argument $_ -- ignored" );
        }
    }

#
#   Is this a ProductionOnly build, then we don't need the debug code and data
#   when building a THX. Determine, if this is a ProductionOnly build.
#
foreach  ( @{$::BUILDINFO{$::ScmPlatform}{ARGS}} )
{
    if ( m~^--OnlyProd~ )
    {
        $Toolset_Production_Only = 1;
        last;
    }
}

#
#   Definitions common to all platforms
#   These will be picked up when no platform has been defined: ie when
#   simply building for MOS68K or MOSCF
#
#   Note: _MICROTEC     is predefined by the compiler
#
    unless ( $no_defines )
    {
        push @defines, 'MOS';
        push @defines, '_MOS';
        push @defines, '_MOS_=1';
        push @defines, '_MOS_PERTH_=1';
        push @defines, 'MICROTEC=1';
        push @defines, 'MRI=1';
        push @defines, 'BIG_ENDIAN=1';
        push @defines, 'CcCpuBigEndian=1';
        push @defines, 'CcSupervisor=$(MODE_CCSUPERVISOR)';
        push @defines, 'CcCpu=$(mri_cpu_code)';
    }

#
#   Platform specific definitions
#   Set default code and data for development purposes only
#   This can be overridden
#
    if ( $Toolset_Product eq "GAK" || $Toolset_Product eq "TPT" )
    {
        # Example only
        #push @defines, '	SSM_DV';
        #push @defines, '	DES_ALIGN_CHECK';
        #push @defines, '	AMCCIF=15';
        #push @defines, '	PACKED=packed';

        if ( $flavour eq  '68k' )
        {
            $Toolset_DebugCode = "08100000H";
            $Toolset_DebugData = "0800800CH";
        }
        else
        {
            $Toolset_DebugCode = "08200000H";
            $Toolset_DebugData = "0800800CH";
        }
    }
    elsif ( $Toolset_Product eq "PCP" )
    {
        $board = "08200000H,0800800CH" if ( $board =~ m/development/i );
        $Toolset_DebugCode = "08100000H";
        $Toolset_DebugData = "0800800CH";
    }
    elsif ( $Toolset_Product eq "VCP" )
    {
        $Toolset_DebugCode = "08100000H";
        $Toolset_DebugData = "0800800CH";
    }
    elsif ( $Toolset_Product eq "TP5" or $Toolset_Product eq "PICP" )
    {
        $board = "08000000H,0400800CH" if ( $board =~ m/green/i );
        $Toolset_DebugCode = "05C00000H";
        $Toolset_DebugData = "0400800CH";
    }
    elsif ( $Toolset_Product eq "SSU" )
    {
    #    $Toolset_DebugCode = "08100000H";
    #    $Toolset_DebugData = "0800800CH";
    }
    elsif ( $Toolset_Product eq "DDU" )
    {
    #    $Toolset_DebugCode = "08100000H";
    #    $Toolset_DebugData = "0800800CH";
    }
    elsif ( $Toolset_Product eq "HCP" )
    {
    #    $Toolset_DebugCode = "08100000H";
    #    $Toolset_DebugData = "0800800CH";
    }
    elsif ( $Toolset_Product eq "OBFTP" )
    {
        $Toolset_DebugCode = "08200000H";
        $Toolset_DebugData = "0800800CH";
    }
    elsif ( $Toolset_Product )
    {
        Message( "mos_mri: Unknown product: $Toolset_Product -- ignored" )
            unless ( $board );
    }

    #
    #   Decode any --board option
    #   This will override any defaults
    #
    if ($board )
    {
        if ( $board =~ m~(0[0-9A-F]+H),(0[0-9A-F]+H)~i )
        {
            $Toolset_DebugCode = $1;
            $Toolset_DebugData = $2;
            Message("Building for a $Toolset_Product DEVELOPMENT board: Code:$Toolset_DebugCode, Data:$Toolset_DebugData");
        }
        else
        {
            Error( "Bad board definition: $board",
                   "Expecting two hex numbers of the form 012345H" );
        }
    }


if ( $Toolset_Product && (! $Toolset_DebugCode || ! $Toolset_DebugData ))
{
    Message( "mos_mri: $Toolset_Product: Debug Code and Data not specified" );
}

#.. Standard.rul requirements
#
    $::s = 'asm';             # Assembler source file
    $::o = 'obj';             # Object file
    $::a = 'lib';             # Library file
    $::so = 'thx';            # Shared library
    $::exe = '.abs';          # Dummy, Cannot generate executables

#.. Toolset configuration
#
    $::ScmToolsetVersion = "1.0.0";               # our version
    $::ScmToolsetGenerate = 0;                    # generate optional
    $::ScmToolsetProgDependancies = 0;            # handle Prog dependancies myself		7 "I:\jats_cbuilder\JATS\MASS_Dev_Infra\core_devl\CFG\TOOLSET\ACEX.PL"

#.. Define MRI environment
#
    #
    #   Define initialisation targets
    #   These will be used to ensure that correct versions of the toolset are present
    #
    Init( "mri", "mri2" );

    ToolsetDefine ( "#################################################" );
    ToolsetDefine ( "# MOS MRI compiler version" );
    ToolsetDefine ( "#" );
    ToolsetDefine ( "mri_ver         = $version" );
    ToolsetDefine ( "mri_type        = $flavour" );
    ToolsetDefine ( "" );
    ToolsetDefine ( "#" );
    ToolsetDefines( "mos_mri_${flavour}.def" );
    ToolsetRules  ( "mos_mri.rul" );
    ToolsetRules  ( "standard.rul" );

    PlatformEntry( "MRI_DEFINES\t=",    "\n", "\\\n\t", "", @defines )
        if ( scalar @defines );

    #
    #   Other toolsets used
    #
    PlatformDefine ("LINT_COFILE\t= MOS_MRI.LNT");
    PlatformDefine ("LINT_PRJ_FILE\t=lint.mri");
    ToolsetRequire( "pclint" );                 # using pclint

#
#   The debug files need to be compiled up with absolute paths to the source files
#   The easiest way to do this is with the makefile rules created with absolute
#   paths. Set a global flag to enable this option
#
    $::UseAbsObjects = 1;


#.. Extend the CompilerOption directive
#   Create a standard data structure
#   This is a hash of hashes
#       The first hash is keyed by CompileOption keyword
#       The second hash contains pairs of values to set or remove
#
    %::ScmToolsetCompilerOptions =
    (
        'ccsupervisor'          => { 'MODE_CCSUPERVISOR' , '1' },

        #
        #   When using MOS fast intermodule calls the optimizer will preload commonly
        #   used memory addresses into a register BEFORE the GDP has been correctly set
        #   up. Use the following option to supress this optimisation
        #
        'noglobaloptimization'  => { 'NO_OPT_GLOBAL' , '1' },

        #
        #   To enable 32-bit relative PC addressing on platforms that
        #   don't have this as a default
        #
        'longrelative'    => { 'USE_32BIT_RELATIVE' , '1' },
        'nolongrelative'  => { 'USE_32BIT_RELATIVE' , undef },

        #
        #   Flag the buildng of the MOS OS
        #   
        'buildmosos'     => {'BUILD_MOS_OS', '1'},
        
    );

    #
    #   Set default options
    #       $::ScmCompilerOpts{'xxxx'} = 'yyy';
    $::ScmCompilerOpts{'MODE_CCSUPERVISOR'} = '0';
    $::ScmCompilerOpts{'NO_OPT_GLOBAL'} = undef;
    $::ScmCompilerOpts{'USE_32BIT_RELATIVE'} = undef;
    $::ScmCompilerOpts{'BUILD_MOS_OS'} = undef;
}

##############################################################################
#   ToolsetPreprocess()
#       Process collected data before the makefile is generated
#       This, optional, routine is called from within MakefileGenerate()
#       It allows the toolset to massage any of the collected data before
#       the makefile is created
#
##############################################################################

sub ToolsetPreprocess
{
    #
    #   If the user has specified a Prog or Shared library, then the
    #   tools within this file will need to be able to access
    #   a few external resouces. These will be provided by packages
    #   that should exist
    #
    #
    if ( $#::TESTPROGS >= 0 || $#::PROGS >= 0 || $#::SHLIBS >= 0)
    {
        my %need = ( "brt.exe"          => "TOOL_BRT",
                     "modcrc.exe"       => "TOOL_MODCRC",
                     "rel.exe"          => "TOOL_REL",
                     "vclickpaths.exe"  => "TOOL_VPATHS"
                   );
        my %found = ();

        #
        #   Locate the required files
        #
        for my $program ( keys( %need ))
        {
            if ( my $path = ToolExtensionProgram( $program ) )
            {
                $found{ $need{$program} } = $path;
                delete( $need{$program} );
            }
        }

        ::Error( "Tool program(s) required by toolset not found:",
                  sort( keys %need),
                  "Check that the daf_tools and mos_tools packages are present" )
            if ( scalar keys %need );

        #
        #   Determine the name of the MOS global library
        #   Old MOS builds provided a library named glob.lib
        #   Newer MOS builds provide a library name globP.lib or globD.lib
        #       When building the MOS OS use the newer form
        #
        my $globFound = '';
        my $globJatsFound = '' ;
        unless ($::ScmCompilerOpts{'BUILD_MOS_OS'}) {
            foreach my $entry ( getPackageList() ) {
                foreach my $libdir ($entry->getLibDirs(3)) {
                    $globFound     = $libdir if ( -f CatPaths($libdir, 'glob.lib') );
                    $globJatsFound = $libdir if ( -f CatPaths($libdir, 'globP.lib') );
                    $globJatsFound = $libdir if ( -f CatPaths($libdir, 'globD.lib') );
                }
            }

            unless ($globJatsFound) {
                $globName = 'glob';
            }
        }

        if ($globFound && $globJatsFound ) {
            Warning("Both glob.lib and glob[PD].lib found - using glob.lib")
        }
        ::Debug("Glob library: $globName");

        #
        #   Generate the definitions
        #

        ToolsetDefine ( "#################################################" );
        ToolsetDefine ( "#  The path to tools required to build MOS Programs" );
        ToolsetDefine ( "#" );
        for my $defn ( keys %found )
        {
            ToolsetDefine ( "$defn := $found{$defn}" );
        }
        ToolsetDefine ( "" );
        ToolsetDefine ( "#  The drive path to prefix to the vision click paths" );
        EnvImport( "GBE_DRV" );
        ToolsetDefine ( "GBE_VCLICKDRV = $::GBE_DRV" );
    }
}

###############################################################################
#   ToolsetCC( $source, $obj, \@args )
#       This subroutine takes the user options and builds the rule(s)
#       required to compile the source file 'source' to 'obj'
#
#   Implementation Note:
#   The MRI compilers that are being used have a problem.
#   If the source filename is relative and longer that ~80 characters and the
#   -Gf switch is being used, then the compiler warns that the pathname is
#   too long to be stored in the ABS file. It then stores the relative name to
#   the file in thr ABS file. This confuses visionclick and vclickpaths
#
#   If the source file is an absolute path, then none of these problems
#   occur, BUT the displayed error messages get chopped so that the user
#   cannot determine the file being compiled.
#
#   Solution:
#       * Give the compiler an absolute path name
#       * Display a shortened filename on the JATS output
#
###############################################################################

sub ToolsetCC
{
    MakePrint( "\n\t\$(CC)\n" );
}

###############################################################################
#   ToolsetCCDepend( $depend, \@sources )
#       This subroutine takes the user options and builds the
#       rule(s) required to build the dependencies for the source
#       files 'sources' to 'depend'.
#
###############################################################################

sub ToolsetCCDepend
{
    MakePrint( "\t\$(CCDEPEND)\n" );
}


###############################################################################
#   ToolsetCXX( $source, $obj, \@args )
#       This subroutine takes the user options and builds the rule(s)
#       required to compile the source file 'source' to 'obj'
#
###############################################################################

sub ToolsetCXX
{
    MakePrint( "\n\t\$(CXX)\n" );
}

###############################################################################
#   ToolsetCXXDepend( $depend, \@sources )
#       This subroutine takes the user options and builds the
#       rule(s) required to build the dependencies for the source
#       files 'sources' to 'depend'.
#
###############################################################################

sub ToolsetCXXDepend
{
    ToolsetCCDepend();
}


###############################################################################
#   ToolsetAS( $source, $obj, \@args )
#       This subroutine takes the user options and builds the rule(s)
#       required to compile the source file 'source' to 'obj'
#
###############################################################################

sub ToolsetAS
{
    MakePrint( "\n\t\$(AS)\n" );
}

sub ToolsetASDepend
{
}

###############################################################################
#   ToolsetAR( $name, \@args, \@objs )
#       This subroutine takes the user options and builds the rules
#       required to build the library 'name'.

#
#   Arguments:
#       --xxx                   No arguments currently defined
#
#   Output:
#       [ $(BINDIR)/name$.${a}:   .... ]
#           $(AR)
#
###############################################################################

sub ToolsetAR
{
    my( $name, $pArgs, $pObjs ) = @_;
    my $lib_file = "${name}\$(GBE_TYPE)";
    my $lib_base = "\$(LIBDIR)/$lib_file";
    my $lib_name = "$lib_base.${a}";

    Debug("ToolsetAR");

#.. Parse arguments
#
    foreach $_ ( @$pArgs ) {
        if (/^--/) {
            Message( "AR: unknown option $_ -- ignored" );
        }
    }

#.. Target
#
    MakeEntry( "$lib_name:\t", "", "\\\n\t\t", ".$::o", @$pObjs );
    MakePrint( "\n\t\$(AR)\n\n" );

}

###############################################################################
#   ToolsetARLINT( $name, \@args, \@objs )
#       This subroutine takes the user options and builds the rules
#       required to build the library 'name'.
#
#   Arguments:
#       --xxx                   No arguments currently defined
#
#   Output:
#       [ $(LIBDIR)/name$_lint:   .... ]
#           $(ARLINT)
#
###############################################################################

sub ToolsetARLINT
{
    PCLintAR( @_ );
}

###############################################################################
#   ToolsetARMerge()
#       Generate the recipe to merge libraries.
#       The dependency list is created by the caller.
#
###############################################################################

sub ToolsetARMerge
{
    MakePrint( "\n\t\$(ARMERGE)\n\n" );
}


###############################################################################
#   ToolsetSHLD $name, \@args, \@objs, \@libraries )
#       This subroutine takes the user options and builds the rules
#       required to link a shared library with any associated stub files
#
#   Arguments:
#       --xxx                   No Arguments currently specified
#
#       Linker specific:
#       --Data                  Generate a Data Module
#       --Debug                 Generate a debug module
#       --DebugCode=nnnnnH      Generate a debug module with code at address
#       --DebugData=nnnnnH      Generate a debug module with data at address
#       --Rel=file              Specify the Release file
#       --Implib=objfile        Specify an import library object
#       --StubOnly              Only generate the stub library
#       --BinaryImage           Generate binary image instead of a THX file
#
#   Output:
#
#       name.thx                - Loadable module
#       name.lib                - Module interface stub library
#       name.abs                - Precursor to .thx
#       name_o.abs              - Used to generate relocation information
#       name_0.abs              - Used to generate relocation information
#
#       name_debug.bdx          - File for debugger
#       name_debug.ab           - File for debugger
#       name_debug.abs          - Precursor to .bdx and .ab files
#
#       This is a very complicated process:
#           Generate stub library
#           Create module header object file
#           Link all at one address
#           Link all at another address
#           Determine relocation information
#           Compile up relocation information
#           Link all with relocation information
#           Create VisionClick debug files
#           Generate CRC over module
#
#   $(LIBDIR)/name.thx $(BINDIR)/name.bdx $(BINDIR)/name.ab :
#                       $(BINDIR)/name.abs
#
#   $(LIBDIR)/name.abs :
#                       objs ....
#                       libs ....
#                       $(OBJDIR)/linker_cmd_file
#
#   $(LIBDIR)/linker_cmd_file :
#                       $(GBE_PLATFORM).mk
#                       ...
###############################################################################

sub ToolsetSHLD
{
    my( $name, $pArgs, $pObjs, $pLibs ) = @_;
    my $module_type = '';
    my $debug_code = $Toolset_DebugCode || 0;
    my $debug_data = $Toolset_DebugData || 0;
    my( $u_rel_file, $rel_file, $head_file, $implib, $stub_only, $bin_image);
    my $pSlibs;


#.. Parse arguments
#
    foreach $_ ( @$pArgs )
    {

    #.. Target specific
    #

    #.. Toolset specific
    #
        if (/^--Data$/) {                       # Generate a data module
            $module_type  = "data";

        } elsif (/^--Acon$/) {                  # Generate an ACON  module
            $module_type  = "acon";

        } elsif (/^--Rel=(.*)/) {               # The base REL file
            $u_rel_file = $1;

        } elsif (/^--Implib=(.*)/) {            # The import library object file
            $implib = $1;

        } elsif (/^--Stubonly/) {               # Only generate the stub library
            $stub_only = 1;

        } elsif (/^--BinaryImage/) {            # Generate binary image instead of a THX file
            $bin_image = 1;

        } elsif (/^--DebugData=(.*)/) {         # Generate a debug module
            $debug_data = $1;
            $module_type  = "debug";

        } elsif (/^--DebugCode=(.*)/) {         # Generate a debug module
            $debug_code = $1;
            $module_type  = "debug";

        } else {
            Message( "Prog: unknown option $_ -- ignored" );
        }
    }

#
#   Cannot create binaries unless we know where to place them
#   This error could be detected earlier, but by detecting it only when
#   we need the values so that we can add new product groups without
#   knowning all the details.
#
unless ( $Toolset_Production_Only )
{
    Error( "mos_mri: $Toolset_Product: Debug Code and Data not specified" )
        if ( ! $debug_data || ! $debug_code );
    
}
    
#
#   Sanity check
#       - Ensure the use has provided a REL file
#
unless ( $u_rel_file )
{
    $u_rel_file = "$name.rel";
    Warning( "Prog: Rel file not provided. Using $u_rel_file" );
}

#
#   Locate the true path of the provided REL file
#   If it is a generate file so it will be in the SRCS hash
#   Other wise the use will have to use Src to locate the file
#
    $rel_file = MakeSrcResolve ( $u_rel_file );

#
#   Locate the true path of the head.asm file
#   This WILL be located within an external package as it is provided
#   by the MOS hardware package.
#
if ($::ScmCompilerOpts{'BUILD_MOS_OS'})
{
    # Building the MOS OS
    # The head.asm file will be foound in the local in directory
    $head_file = '$(INCDIR_LOCAL)/head.asm';
}
else
{
    #
    #   Non-OS build
    #   The head.asm file will be found in an external package
    #   
        $head_file = MakeSrcResolveExtended ( 1, "head.asm" );
}

#
#   If we are also creating an import (stub) library then remove
#   the stub library object file from the list of user provided objects
#   Done to allow the use of @OBJS in a library object list
#
if ( $implib )
{
    my @newobjs;
    for ( @$pObjs )
    {
        push @newobjs, $_
            unless ( m~/$implib$~ );
    }
    $pObjs = \@newobjs;
}

#
#   Extend the list of libraries with MOS specific libraries
#   This list may need multiple passes and will be replicated. Do not include
#   the compiler RTL library in this list as it will cause problems. It must be
#   linked last and linked only once.
#
    push( @$pLibs, $globName );

#   Create a list of system (RTL) libraries
#   We only want to use the compiler RTL library as a last resort and will only
#   make one pass over it.
#
    push( @$pSlibs, '$(mri_linker_lib)' );

#
#   Create a ABSRuleGenerator
#   This inherits from a a ToolsetPrinter and extends it to
#   allow addition data to be held
#
    my ($io) = ABSRuleGenerator::New( $name, $pObjs, $pLibs, $pSlibs );


########################################################################
#
#   Create a stub library to allow inter-module calls
#
if ( $implib )
{
    $io->Label( "Import(stub) library", $name );
    my $stub_lib = "\$(LIBDIR)/${name}\$(GBE_TYPE).${a}";

    #
    #   Rules and recipe to generate the stub library
    #
    #   If the implib was not named in the object list to this SharedLib
    #   then it will not be in OBJSOURCE and will not have a rule
    #
    #
    $::OBJSOURCE{"$name/$implib"} = $::OBJSOURCE{"$implib"}
        unless( $::OBJSOURCE{"$name/$implib"} );
    $io->Prt( "$stub_lib:\t\$(OBJDIR)/$name/$implib.$::o\n" );
    $io->Prt( "\t\$(AR)\n" );
    $io->Newline();
            
    #
    #   Files to be cleanup up
    #
    ToolsetGenerate( $stub_lib );

    #
    #   If the THX is being packaged/installed then add the static
    #   stub library to the packaging lists as a static library.
    #   This will allow the stub library to be installed with the
    #   static libraries and thus allow DLL's with mutual imports
    #
    PackageShlibAddLibFiles ($name, $stub_lib );

    #
    #   Add the stub library to the list of libraries being created
    #
    push @::LIBS, $name;
    
}

#
#   If we are only creating a sub library, then out work is done
#
if ( $stub_only )
{
    Error ("Request for stub library without specifying the Import file")
        unless ($implib);
    return;
}

########################################################################
#
#   Create the module header
#   This is a two step process
#       1) Create the head.inc file from the modules REL file
#       2) Compile the head.asm file
#
#   Note: "head.inc" is a fixed filename. It is created on demand
#         and left around
#

    $io->Label( "Module Header", $name );
    $io->Prt( "\$(OBJDIR)/${name}/head.$::o: $head_file $rel_file");
    $io->Prt( "\n\t\$(call AS_HEAD,$rel_file,$head_file,\$(OBJDIR)/${name}/head.$::o,\$(OBJDIR)/${name}/head.inc)\n" );
    $io->Newline();

    ToolsetObj     ( "\$(OBJDIR)/${name}/head" );
    ToolsetGenerate( "\$(OBJDIR)/${name}/head.inc" );
    ToolsetGenerate( "\$(OBJDIR)/head.inc" );

#
#   Create rules and recipes to generate two .abs files that are
#   used to generate relocation information
#
    $io->GenAbsFile( "OBJDIR", "_o", "S[3]", $module_type, "800000H", "100000H" );
    $io->GenAbsFile( "OBJDIR", "_0", "S[3]", $module_type, "400000H", "000000H" );

    #
    #   Create the relocation information from the two .abs files
    #   This file will be used to add to other abs files
    #

    $io->Prt( "\$(OBJDIR)/${name}_rtab_d.asm \$(OBJDIR)/${name}_rtab_cd.asm: BRTROOT=${name}\n" );
    $io->Entry( "\$(OBJDIR)/${name}_rtab_d.asm \$(OBJDIR)/${name}_rtab_cd.asm:\t", "", "\\\n\t\t\$(OBJDIR)/", ".abs ", ( "${name}_o", "${name}_0" ) );
    $io->Prt( "\n\t\$(BRT)\n" );
    $io->Newline();

    ToolsetGenerate( "\$(OBJDIR)/${name}_rtab_d.asm" );
    ToolsetGenerate( "\$(OBJDIR)/${name}_rtab_cd.asm" );

    #
    #   Rules to allow the two assembler files to be created
    #   Override user assembler flags to control the assembler environment
    #
    $io->Prt( "\$(OBJDIR)/${name}_rtab_d.$::o: ASFLAGS=-fNOPCR -frel32\n");
    $io->Prt( "\$(OBJDIR)/${name}_rtab_d.$::o: \$(OBJDIR)/${name}_rtab_d.asm");
    $io->Prt( "\n\t\$(AS)\n" );
    $io->Newline();

    $io->Prt( "\$(OBJDIR)/head.$::o: ASFLAGS=-fNOPCR -frel32\n");
    $io->Prt( "\$(OBJDIR)/${name}_rtab_cd.$::o: ASFLAGS=-fNOPCR -frel32\n");
    $io->Prt( "\$(OBJDIR)/${name}_rtab_cd.$::o: \$(OBJDIR)/${name}_rtab_cd.asm");
    $io->Prt( "\n\t\$(AS)\n" );
    $io->Newline();

    ToolsetObj( "\$(OBJDIR)/${name}_rtab_d" );
    ToolsetObj( "\$(OBJDIR)/${name}_rtab_cd" );
    

#
#   Create rules and recipes to generate the final .abs file which will feed into
#   the required .thx file. this file will now have embedded relocation information
#
    $io->GenAbsFile( "LIBDIR", "\$(GBE_TYPE)", "S[3]", $module_type, "400000H", "000000H", "\$(OBJDIR)/${name}_rtab_cd"  );

#
#   Create rules and recipes to generate a debug-able .abs file
#   This is a totally different beast and is then used to
#   create some debugger friendly files
#
    $io->GenAbsFile( "LIBDIR", "\$(GBE_TYPE)_debug", "IEEE", "debug", $debug_data, $debug_code, "\$(OBJDIR)/${name}_rtab_d" );


########################################################################
#
#   VisionClick support
#   Physivcal files will not be generated if the tool it not available
#   Either generate the files or provide phony targets
#
    $io->Label( "VisionClick support", $name );
    $io->Prt( "ifdef VISIONCLICK\n".
              "\$(LIBDIR)/${name}\$(GBE_TYPE)_vpaths.txt ".
              "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.bdx ".
              "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abx ".
              "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.ab: ".
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abs".
              "\n\t\t\$(call VCLICK, \$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abs,\\".
              "\n\t\t               \$(LIBDIR)/${name}\$(GBE_TYPE)_vpaths.txt,\\".
              "\n\t\t               \$(GBE_VCLICKDRV) )".
              "\nelse".
              "\n.PHONY:\t\$(LIBDIR)/${name}\$(GBE_TYPE)_vpaths.txt".
              "\n.PHONY:\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.bdx".
              "\n.PHONY:\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abx".
              "\n.PHONY:\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.ab".
              "\nendif\n\n" );

    #
    #   Vision Click files for cleanup
    #
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.bdx" );
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.ab" );
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abx" );
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abg" );
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE)_vpaths.txt" );

    #
    #   Add the Visionclick files to the package lists
    #   These will only be packaged if VISIONCLICK is defined
    #
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.bdx" , 'defined=VISIONCLICK', 'Class=debug' );
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.ab"  , 'defined=VISIONCLICK', 'Class=debug' );
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abx" , 'defined=VISIONCLICK', 'Class=debug' );
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE)_vpaths.txt", 'defined=VISIONCLICK', 'Class=debug' );
    

########################################################################
#
#   Rules and recipes to create the .THX (.BIN) file
#   This ties together all the previous components
#
#
    my $sh_ext = $bin_image ? 'bin' : $::so;

    $io->Label( "MOS Module", $name );
    $io->Prt( "\$(LIBDIR)/${name}\$(GBE_TYPE).$sh_ext :" .
              "\\\n\t\t\$(OBJDIR)/${name}_o.abs " .
              "\\\n\t\t\$(OBJDIR)/${name}_0.abs " .
              "\\\n\t\t\$(OBJDIR)/${name}_rtab_cd.asm " .
              "\\\n\t\t\$(OBJDIR)/${name}_rtab_d.asm " .
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE).abs " .
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abs " .
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE)_vpaths.txt ".
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.bdx ".
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abx ".
              "\\\n\t\t\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.ab "
            );

    if ( $bin_image)
    {
        $io->Prt( "\n\t\t\$(MODCRC_BIN)\n");
    }
    else
    {
        $io->Prt( "\n\t\t\$(MODCRC)\n");
    }

    #
    #   Register generated file for cleanup
    #   The MODCRC process generates a .bak file. Ensure that it gets removed
    #
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE).$sh_ext" );
    ToolsetGenerate( "\$(LIBDIR)/${name}\$(GBE_TYPE).bak" );

    #
    #   Specify the files to be packaged as part of the shared library
    #
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE).$sh_ext" );
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE)_debug.abs", 'Class=debug' );
}


#-------------------------------------------------------------------------------
# package       : ABSRuleGenerator
#
# Description   : Package to contain data to generate rules to create
#                 ABS files.
#
#                 This is implemented as a class to allow blocks of
#                 data to be simply maintained
#
#                 This class ISA ToolsetPrinter too
#
# Parameters    : name      - Basic name of the library
#                 pObjs     - Ref to an array of object files to be linked
#                 pLibs     - Ref to an array of libraries to be linked
#                 pSlibs    - Ref to an array of system libraries to be linked
#                             These libraries will only be linked ONCE
#
package ABSRuleGenerator;

    use vars qw(@ISA);
    @ISA = ("ToolsetPrinter");

sub New
{
    my ($name, $pObjs, $pLibs, $pSlibs) = @_;

    my $self = ToolsetPrinter::New();

    $self->{name}  = $name;
    $self->{pObjs} = $pObjs;
    $self->{pLibs} = $pLibs;
    $self->{sLibs} = $pSlibs;

    return bless $self, __PACKAGE__;
}

#-------------------------------------------------------------------------------
# Function        : GenAbsFile
#
# Description     : Internal helper function to generate an ABS file
#                   with desirable characteristics
#
#                   Note: This function is not within the ToolsetSHLD to
#                         make closure problems obvious
#
# Inputs          : $1      - Name of the output directory (LIBDIR or OBJDIR)
#                   $2      - basename of the output file
#                   $3      - basename sufix
#                   $4      - Type of output IEEE /S[3]
#                   $5      - Kind of module - "acon", "data", "debug" or ""
#                   $6      - Base of the data segment
#                   $7      - Base of the code segment
#                   $8      - Extra (internal) object file to be linked in
#
# Returns         :
#
sub GenAbsFile
{
    my ( $io, $dir, $suf, $otype, $kind, $data_base, $code_base, $eObjs ) = @_;
    my $name  = $io->{'name'};
    my $pLibs = $io->{'pLibs'};
    my $pSlibs = $io->{'sLibs'};
    my $lib = $name . $suf;

    #
    #   Generate a full list of object files
    #
    my @allObjs = @{$io->{'pObjs'}};
    push @allObjs, $eObjs
        if ( $eObjs);

#
#.. Linker command file
#
#   Piecing together a variable $(name_ld) which ends up in the command file.
#   This bit of magic will be performed by the LDABS recipe
#
    $io->Reset();                                   # Reset internal state
    $io->SetTag( "${lib}_shld" );                   # macro tag
    $io->Label( "Linker commands", $lib );          # label

    $io->Cmd("FORMAT      $otype" );
    $io->Cmd("CHIP	    \$(mri_cpu_type)" );
    $io->Cmd("LISTMAP     CROSSREF,INTERNALS,PUBLICS" );

    $io->Cmd("DEBUG_SYMBOLS" )        if ( $kind eq "debug" );

    unless ( $kind eq "acon" || $kind eq "data" )
    {
        $io->Cmd("MERGE vars  StartPixInit,pixinit,EndPixInit" );
        $io->Cmd("MERGE vars  StartInitFini,initfini,EndInitFini" );
        $io->Cmd("MERGE vars  cxx_rtti,cxx_edt" );
        $io->Cmd("INITDATA    vars" );
        $io->Cmd("INDEX       ?A5,zerovars" );
        $io->Cmd("EXTERN      __mosSoftTrap" );
    }

    if ( $kind eq "data" )
    {
        $io->Cmd("SECT        header = 0H" );
        $io->Cmd("ORDER       header,ascode,code,const" );
        $io->Cmd("ORDER       modtitle,lastsync" );
    }
    elsif ( $kind eq "acon" )
    {
        $io->Cmd("SECT        header = 0H" );
        $io->Cmd("ORDER       header,const,code,ascode" );
        $io->Cmd("ORDER       modtitle,lastsync" );
    }
    else
    {
        $io->Cmd("SECT        zerovars = $data_base" );
        $io->Cmd("SECT        header = $code_base" );

        $io->Cmd("ORDER       zerovars,vars,uninivars" )      if ( $kind eq "debug" );
        $io->Cmd("ORDER       header,ascode,code" );
        $io->Cmd("ORDER       literals,strings,const" );
        $io->Cmd("ORDER       ??INITDATA,modtitle,rellist,lastsync" );
        $io->Cmd("ORDER       zerovars,vars,uninivars" )      unless ( $kind eq "debug" );
        $io->Cmd("ORDER       stack" )                        if ( $kind eq "debug" );
    }
    $io->Cmd("ALIGN       lastsync,4" );
    $io->Newline();

    #
    #   Must load GLOB.LIB first so that "well-known" variables
    #   in zerovars are at a known location
    #
    $io->Prt("#   Load the Global Library first\n");
    $io->Newline();
    $io->LibList( $name, [$globName], \&ToolsetLibRecipe );
    $io->Newline();

    $io->Prt("#   Load the module header and target specfic library\n");
    $io->Prt("#\n");
    $io->Cmd("LOAD    \$(OBJDIR)/${name}/head.$::o" );
    $io->Newline();

    $io->Prt("#   List all the object files to be loaded\n");
    $io->Prt("#\n");

    $io->ObjList( $name, \@allObjs, \&ToolsetObjRecipe );
    $io->Newline();

    $io->Prt("#   Load the library files three times to overcome single pass linker problems\n");
    $io->Prt("#\n");

    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );
    $io->Newline();
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );
    $io->Newline();
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );
    $io->Newline();

    $io->LibList( $name, $pSlibs, \&ToolsetLibRecipe );
    $io->Newline();

    $io->Prt("#.. Map file options\n");
    $io->Cmd("LISTMAP	LENGTH 64");
    $io->Cmd("LISTMAP	CROSSREF,INTERNALS,PUBLICS/by_addr");
    $io->Cmd("END");
    $io->Newline();

    #
    #   Create the shared library dependency information
    #
    my $dep = $io->SetShldTarget( $lib, $dir );

    #
    #   Create the rules and recipes to create the required file
    #
    $io->Prt( "\$($dir)/$lib.abs:\tSHBASE=${name}${suf}\n" );
    $io->Prt( "\$($dir)/$lib.abs:\tSHNAME=${name}${suf}\n" );
    $io->Prt( "\$($dir)/$lib.abs:\t\$(SCM_MAKEFILE)" );
    $io->Prt( "\\\n\t\t$dep " );
    $io->Entry( "", "", "\\\n\t\t", ".$::o ", @allObjs );
    $io->Prt( "\\\n\t\t\$(OBJDIR)/${name}/head.$::o " );
    $io->Prt( "\n\t\$(SHLDABS)\n" );
    $io->Newline();


    #.. Dependency link,
    #   Create a library dependency file
    #       Create command file to build applicaton dependency list
    #       from the list of dependent libraries
    #
    #       Create makefile directives to include the dependency
    #       list into the makefile.
    #
    $io->DepRules( $pLibs, \&ToolsetLibRecipe, "\$($dir)/$lib.abs" );
    $io->DepRules( $pSlibs,\&ToolsetLibRecipe, "\$($dir)/$lib.abs" );
    $io->SHLDDEPEND( $lib, $lib );

#.. Cleanup rules
#
    ::ToolsetGenerate( "\$($dir)/$lib.ld" );
    ::ToolsetGenerate( "\$($dir)/$lib.abs" );
    ::ToolsetGenerate( "\$($dir)/$lib.map" );

}

########################################################################
#
#   Generate a linker object recipe.  This is a helper function used 
#   within this toolset.
#
#   Arguments:
#       $io         I/O stream
#
#       $target     Name of the target
#
#       $obj        Library specification
#
########################################################################

sub ToolsetObjRecipe
{
    my ($io, $target, $obj) = @_;

    $io->Cmd("LOAD	$obj.$::o");
}

########################################################################
#
#   Generate a linker/depend library recipe.  This is a helper function
#   used within this toolset.
#
#   Arguments:
#       $io         I/O stream
#
#       $target     Name of the target
#
#       $lib        Library specification
#
#       $dp         If building a depend list, the full target name.
#
########################################################################

sub ToolsetLibRecipe
{
    my ($io, $target, $lib, $dp) = @_;

    if ( !defined($dp) ) {                      # linker
        $io->Cmd("LOAD	@(vpath2,$lib.$::a,MRI_LIB)" );

    } else {                                    # depend
        $io->Cmd( "$dp:\t@(vlib2,$lib.$::a,MRI_LIB)" );
    }
}

package main;

###############################################################################
#   ToolsetSHLDLINT $name, \@args, \@objs, \@libraries )
#       This subroutine takes the user options and builds the rules
#       required to lint the program 'name'.
#
#   Arguments:
#       (none)
#
#   Output:
#       [ $(LIBDIR)/$name_lint:   .... ]
#           $(SHLIBLINT)
#
###############################################################################

sub ToolsetSHLDLINT
{
    PCLintSHLIB( @_ );
}


#.. Successful termination
1;

