classdef (Sealed) PILApplicationDependencies
    %PILAPPLICATIONDEPENDENCIES Class of static helper functions to capture
    %common PIL application dependencies.

%   Copyright 2020-2023 The MathWorks, Inc.
        
    properties (Constant)
        PILPath = fullfile(matlabroot, 'toolbox', 'rtw', 'targets', 'pil', 'c'); 
        ExternalIncludesPath = fullfile(matlabroot, 'extern', 'include');
        XILTgtAppSvcIncludeDir = fullfile(coder.connectivity.PILApplicationDependencies.ExternalIncludesPath, 'coder', 'connectivity', 'XILTgtAppSvc');
        RTIOStreamUtilsPath = fullfile(matlabroot,'toolbox','coder','rtiostream','src','utils');
        RTIOStreamInclsPath = fullfile(matlabroot, 'toolbox', 'coder', 'rtiostream', 'src');
        CoderAssumptionAppInclsPath = fullfile(coder.connectivity.PILApplicationDependencies.ExternalIncludesPath, 'coder', 'connectivity', 'CoderAssumpTgtAppSvc');
    end
    
    methods (Static=true)
        
        function fileList = getSourceFiles(componentArgs)
                        
            fileList = { fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_interface_lib.c'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_data_stream.c'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_services.c'), ... 
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xilcomms_rtiostream.c'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_rtiostream.c'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.RTIOStreamUtilsPath, 'rtiostream_utils.c') ...
                       };                 
                   
            if componentArgs.isSIL
                
                fileList = [fileList, ...
                           {fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'target_io.c')}];
            end
            
            if componentArgs.CoderAssumptionsEnabled
                
                staticCASrcs = coder.assumptions.CoderAssumptions.getXILAppStaticSourceFileNames();
                staticCASrcs = cellfun(@(f) fullfile(coder.connectivity.PILApplicationDependencies.PILPath, f), staticCASrcs, 'UniformOutput', false);
                
                fileList = [fileList, ... 
                           staticCASrcs, ... 
                           {fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'coder_assumptions_rtiostream.c')}];
            end
        end
        
        function fileList = getHeaderFiles(componentArgs)
                       
            fileList = { fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_interface.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_interface_common.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_interface_lib.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_interface_lib_private.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_data_stream.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'xil_common.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'comms_interface.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'rx_tx_buffer_sizes.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.XILTgtAppSvcIncludeDir, 'XILTgtAppSvc.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.XILTgtAppSvcIncludeDir, 'XILTgtAppSvc_CInterface.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.RTIOStreamUtilsPath, 'rtiostream_utils.h'), ...
                         fullfile(coder.connectivity.PILApplicationDependencies.RTIOStreamInclsPath, 'rtiostream.h') ...
                       };
                        
            if componentArgs.isSIL
                
                fileList = [fileList, ...
                           {fullfile(coder.connectivity.PILApplicationDependencies.PILPath, 'target_io.h')}];
            end
                   
            if componentArgs.CoderAssumptionsEnabled
                
                staticCAIncls = coder.assumptions.CoderAssumptions.getXILAppStaticHeaderFileNames();
                staticCAIncls = cellfun(@(f) fullfile(coder.connectivity.PILApplicationDependencies.PILPath, f), staticCAIncls, 'UniformOutput', false);
                
                fileList = [fileList, ... 
                           staticCAIncls, ... 
                           {fullfile(coder.connectivity.PILApplicationDependencies.CoderAssumptionAppInclsPath, 'CoderAssumpTgtAppSvc_CInterface.h')}];
            end
        end
        
        function dirList = getIncludeDirectories(componentArgs)
            
                dirList = { coder.connectivity.PILApplicationDependencies.PILPath, ...
                            coder.connectivity.PILApplicationDependencies.ExternalIncludesPath, ...
                            coder.connectivity.PILApplicationDependencies.XILTgtAppSvcIncludeDir, ...
                            coder.connectivity.PILApplicationDependencies.RTIOStreamUtilsPath, ...
                            coder.connectivity.PILApplicationDependencies.RTIOStreamInclsPath };
                        
            if (componentArgs.CoderAssumptionsEnabled)
                dirList{end+1} = coder.connectivity.PILApplicationDependencies.CoderAssumptionAppInclsPath;
            end
        end
        
        function definesList = getCompilerDefines(componentArgs, targetServices)
            
            definesList = {};
            
            definesList{end+1} = ['CODER_ASSUMPTIONS_ENABLED=' num2str(componentArgs.CoderAssumptionsEnabled)];
            
            if componentArgs.isSIL
                
               definesList{end+1} = 'XIL_SIGNAL_HANDLER=1'; 
               
               if ~targetServices.getDataTypeService().getIsByteAddressable()
                   definesList{end+1} = 'HOST_WORD_ADDRESSABLE_TESTING=1';                
               end
               
               denormalConfigValue = componentArgs.getParam('DenormalBehavior');
               lXilCompInfo = componentArgs.getXilCompInfo();
               SILSubnormalDefineName = 'SIL_DISABLE_SUBNORMAL_SUPPORT';
               subnormalSettingInt = coder.connectivity.PILApplicationDependencies.getSILSubnormalDefineValue(...
                   denormalConfigValue, lXilCompInfo);
               definesList{end+1} = [SILSubnormalDefineName '=' num2str(subnormalSettingInt)];
            end
        end

        function silSubnormalDefineValue = getSILSubnormalDefineValue(denormalConfigValue, lXilCompInfo)
            % Get the macro value for 'SIL_DISABLE_SUBNORMAL_SUPPORT'
            featureVal = coder.internal.connectivity.featureOn('DisableSubnormalsForSIL');
            silSubnormalDefineValue = 0;
            
            if ~strcmp(denormalConfigValue,'GradualUnderflow') && (featureVal == 0)
                switch denormalConfigValue
                    case 'FlushToZero'
                        silSubnormalDefineValue = 1;
                    case 'DenormalsAsZeros'
                        silSubnormalDefineValue = 2;
                    otherwise
                        assert(false,'Unexpected setting for DenormalBehavior')
                end
            elseif (featureVal ~= 0)
                silSubnormalDefineValue = featureVal;
            end
            
            [isDenormalSupportedForToolchain, toolchain] = ...
                coder.connectivity.PILApplicationDependencies.toolchainSupportsDenormal(lXilCompInfo);
            if ~isDenormalSupportedForToolchain && silSubnormalDefineValue ~= 0
                silSubnormalDefineValue = 0;
                diagObj = MSLDiagnostic(message('PIL:pil:CannotUseFTZWithLCC', denormalConfigValue, toolchain));
                diagObj.reportAsWarning();
            end
        end

        function [isDenormalSupportedForToolchain, toolchain] = toolchainSupportsDenormal(lXilCompInfo)
            % The LCC toolchain does not support the required header
            % <immintrin.h>, therefore, we are unable to honor FTZ or DAZ
            % denormal behaviors during simulation. In this case we want to
            % disable coder assumptions tests for denormal behaviour and
            % default to Gradual Underflow so that we are still able to
            % simulate (g3070903).

            % Resolve toolchain name from config set value

            if lXilCompInfo.IsToolchainBased
                mexCompStr = lXilCompInfo.ToolchainInfo.Alias{1};
                toolchain = lXilCompInfo.ToolchainInfo.Name;
            else
                % TMF Based
                if ~isempty(lXilCompInfo.ToolchainInfo)
                    % return toolchain name if a toolchain has been
                    % associated with the TMF.
                    toolchain = lXilCompInfo.ToolchainInfo.Name;
                    mexCompStr = lXilCompInfo.ToolchainInfo.Alias{1};
                else
                    mexCompStr = "";
                    toolchain = "";
                end
            end
            isDenormalSupportedForToolchain = ~strcmpi(mexCompStr, 'LCC-x');
        end

        function addTargetIoDependenciesToBuildInfo(buildInfo)
                
            buildInfo.addIncludeFiles('target_io.h', coder.connectivity.PILApplicationDependencies.PILPath);
            buildInfo.addSourceFiles('target_io.c', coder.connectivity.PILApplicationDependencies.PILPath);  
        end
    end
end

