function varargout = hdlsettingsxsg(sys)
% HDLSETTINGSXSG    Helper function for System Generator integration
% 
% HDLSETTINGSXSG(SYS) helps you set up HDL code generation properties for a
% Simulink model that is partially implemented in Xilinx System Generator.
% The argument SYS is a string specifying the full Simulink path to the
% subsystem implemented in System Generator, or the System Generator block
% in that subsystem.
%
% HDLSETTINGSXSG(SYS) does the following:
% 1. Extracts settings from the System Generator block in your model. 
% 2. Sets HDL code generation properties that are compatible with the 
%    extracted settings.
% 3. Specifies a black box implementation for the System Generator 
%    subsystem.
% 4. Returns the control statements generated in 2 & 3 in a new file in the
%    editor.
%
% You can use the generated file to create a new control file for your
% model, or copy and paste the control statements to an existing control
% file.
% 
% T = HDLSETTINGSXSG(SYS) returns the control statements in string T
% instead of a new file.

%   Copyright 2007-2011 The MathWorks, Inc.
%     


% Step 1: Get parameters from System Generator block

[sg_blk sg_sys] = getSysGenPath(sys);
[mdldir strdir] = getSysGenDir(sg_blk);
sg_params = xlgetparams(sg_blk);


% Step 2: Specify implementation for the System Generator subsystem

nl = '\n';
bl = blanks(10);

if strcmpi(sg_params.compilation, 'HDL netlist')
    bboxattr = 'off';
else
    bboxattr = 'on';
end

str = ['%% Use Xilinx black box implementation for the System Generator subsystem' nl ...
    'c.forEach(''' sg_sys ''',...' nl ...
    bl '''built-in/SubSystem'', {},...' nl ...
    bl '''XilinxBlackBox'',...' nl ...
    bl '{''AddClockPort'', ''on'', ''ClockInputPort'', ''clk'',...' nl ...
    bl ' ''AddClockEnablePort'', ''on'', ''ClockEnableInputPort'', ''ce'',...' nl ...
    bl ' ''AddResetPort'', ''off'', ''InlineConfigurations'', ''off'',...' nl ...
    bl ' ''BlackBoxAttributes'', ''' bboxattr '''});' nl];


% Step 3: Specify code generation properties

bl = blanks(6);

str = [str nl ...
    'targetdir = ''hdlsrc'';' nl ...
    'xsgdir = ''' sg_params.directory ''';' nl mdldir];

if strcmpi(sg_params.synthesis_tool, 'xst')
    str = [str 'projectdir = ''iseproj'';' nl];
end

% Set TargetDirectory, and other properties to be compatible with System
% Generator code generation settings
sglang = sg_params.synthesis_language;
sgclk = slResolve(sg_params.sysclk_period, sg_blk);

str = [str nl ...
    'c.set(''TargetDirectory'', targetdir,...' nl ...
    bl '''TargetLanguage'', ''' sglang ''',...' nl ...
    bl '''ClockHighTime'', ' num2str(sgclk/2) ',...' nl ...
    bl '''ClockLowTime'', ' num2str(sgclk/2) ',...' nl ...
    bl '''ResetLength'', 0,...' nl ...
    bl '''TestBenchClockEnableDelay'', 0,...' nl ...
    bl '''InitializeTestBenchInputs'', ''on'');' nl];

% Set HDLSynth[FilePostfix, Init, Cmd, Term] properties to create synthesis
% tcl script for XST or Synplify.
if strcmpi(sg_params.synthesis_tool, 'xst')
    
    if strcmpi(sg_params.compilation, 'HDL netlist')
        str_tcl = [',...' nl bl ' ''set xsg_dir "'' strrep(' strdir ',''\\'',''/'') ''"\\n''' ...
                   ',...' nl bl ' ''source $hdlc_dir/add_sgp.tcl\\n'''];
    else
        str_tcl = '';
    end
    
    str = [str nl ...
       '%% Create XST synthesis script' nl ...
        'c.set(''HDLSynthFilePostfix'', ''_xst.tcl'',...' nl ...
        bl '''HDLSynthInit'',...' nl ...
        bl '[''set hdlc_dir "'' strrep(fullfile(pwd,targetdir),''\\'',''/'') ''"\\n'',...' nl ...
        bl ' ''set proj_dir "$hdlc_dir/../'' projectdir ''"\\n'',...' nl ...
        bl ' ''file mkdir $proj_dir\\n'',...' nl ...
        bl ' ''cd $proj_dir\\n'',...' nl ...
        bl ' ''project new %%s.ise\\n'',...' nl ...
        bl ' ''project set family ' sg_params.xilinxfamily '\\n'',...' nl ...
        bl ' ''project set device ' sg_params.part '\\n'',...' nl ...
        bl ' ''project set package ' sg_params.package '\\n'',...' nl ...
        bl ' ''project set speed ' sg_params.speed '\\n''' ... 
        str_tcl '],...' nl ...
        bl '''HDLSynthCmd'', ''xfile add $hdlc_dir/%%s\\n'',...' nl ...
        bl '''HDLSynthTerm'', ''process run "Synthesize - XST"\\n'');' nl];
        
else % Synplify or Synplify Pro
    
    str = [str nl ...
       '%% Create Synplify synthesis script' nl ...
        'c.set(''HDLSynthFilePostfix'', ''_synplify.tcl'',...' nl ...
        bl '''HDLSynthInit'', ''project -new %%s.prj\\n'',...' nl ...
        bl '''HDLSynthCmd'', ''add_file %%s\\n'',...' nl ...
        bl '''HDLSynthTerm'',...' nl ...
        bl '[''set_option -technology ' sg_params.xilinxfamily '\\n'',...' nl ...
        bl ' ''set_option -part ' sg_params.part '\\n'',...' nl ...
        bl ' ''set_option -package ' sg_params.package '\\n'',...' nl ...
        bl ' ''set_option -speed_grade ' sg_params.speed '\\n'',...' nl ...
        bl ' ''set_option -synthesis_onoff_pragma 0\\n'',...' nl ...
        bl ' ''set_option -frequency auto\\n'',...' nl ...
        bl ' ''set_option -write_apr_constraint 0\\n'',...' nl ...
        bl ' ''project -run synthesis\\n'']);' nl];
end

% Define path to Xilinx simulation libraries
if strcmpi(sglang, 'vhdl')
    libpath = {'unisim', 'simprim', 'XilinxCoreLib'};
    compcmd = {'HDLCompileVHDLCmd', 'vcom'};
else
    libpath = {'unisims_ver', 'simprims_ver', 'XilinxCoreLib_ver'};
    compcmd = {'HDLCompileVerilogCmd', 'vlog'};
end

xenv = getenv('XILINX');
if isempty(xenv)
    xenv = 'C:/Xilinx/';
else
    xenv = [strrep(xenv,'\','/') '/'];
end

str = [str nl ...
    '%% The following paths are the default COMPXLIB output directories for' nl ...
    '%% ModelSim SE. If necessary, replace them with the Unsim, Simprim and' nl ...
    '%% XilinxCoreLib library paths in your working environment.' nl ...
    'unisim_dir = ''' xenv lower(sglang) '/mti_se/' libpath{1} ''';' nl ...
    'simprim_dir = ''' xenv lower(sglang) '/mti_se/' libpath{2} ''';' nl ...
    'xcorelib_dir = ''' xenv lower(sglang) '/mti_se/' libpath{3} ''';' nl];

% Set HDLCompile[Init, VHDLCmd/VerilogCmd] property to include the vcom.do
% script generated by System Generator and vmap commands in the compilation
% script. vcom.do compiles the HDL files for the Xilinx subsystem, while
% the vmap commands map to the pre-compiled Xilinx simulation libraries in
% ModelSim.
str = [str nl ...
    '%% Generate a compilation script that compiles HDL files in the System' nl ...
    '%% Generator target directory, and remains there in order to access other' nl ...
    '%% Xilinx files (such as .mif) that are necessary during HDL simulation.' nl ...
    'c.set(''HDLCompileInit'',...' nl ...
    bl '[''set hdlc_dir "'' strrep(fullfile(pwd,targetdir),''\\'',''/'') ''"\\n'',...' nl ...
    bl ' ''set xsg_dir "'' strrep(' strdir ',''\\'',''/'') ''"\\n'',...' nl ...
    bl ' ''cd $xsg_dir\\n'',...' nl ...
    bl ' ''vmap ' libpath{1} ' "'' unisim_dir ''"\\n'',...' nl ...
    bl ' ''vmap ' libpath{2} ' "'' simprim_dir ''"\\n'',...' nl ...
    bl ' ''vmap ' libpath{3} ' "'' xcorelib_dir ''"\\n'',...' nl ...
    bl ' ''do vcom.do\\n'',...' nl ...
    bl ' ''vlib work\\n''],...' nl ...
    bl '''' compcmd{1} ''', ''' compcmd{2} ' %%s $hdlc_dir/%%s\\n'');' nl];

% Set HDLSim[Cmd, Term] properties to match the settings in the vsim.do
% script generated by System Generator.
if strcmpi(sglang, 'vhdl')

    % Set simulation resolution to ps, and NumericStdWarnings settings
    str = [str nl ...
        'c.set(''HDLSimCmd'', ''vsim -voptargs=+acc -t ps work.%%s\\n'',...' nl ...
        bl '''HDLSimTerm'',...' nl ...
        bl '[''set NumericStdNoWarnings 1\\n'',...' nl ...
        bl ' ''run 0\\n'',...' nl ...
        bl ' ''set NumericStdNoWarnings 0\\n'',...' nl ...
        bl ' ''run -all\\n'']);' nl];
    
else % verilog

    % Set simulation resolution to ps, and simulation libraries
    str = [str nl ...
        'c.set(''HDLSimCmd'',...' nl ...
        bl '[''vsim -voptargs=+acc +nowarnTFMPC -t ps work.%%s '',...' nl ...
        bl ' ''-L UNISIMS_VER -L SIMPRIMS_VER '',...' nl ...
        bl ' ''-L XILINXCORELIB_VER work.glbl work.clock_pkg\\n''],...' nl ...
        bl '''HDLSimTerm'', ''run -all\\n'');' nl];
end


% Step 4: Write code generation settings to new file or string

str = sprintf(str);
if nargout == 0
    hdlneweditorfile(str);
else
    varargout(1) = {str};
end

%--------------------------------------------------------------------------       
function [sg_blk sg_sys] = getSysGenPath(sys)

try
    bt = get_param(sys, 'block_type');
catch me
    bt = '';
end

if strcmp(bt, 'sysgen')
    % Input is System Generator block
    sg_blk = sys;
    sg_sys = get_param(sg_blk, 'Parent');
else
    % Input is subsystem implemented with System Generator blocks
    try
        sg_blk = find_system(sys, 'SearchDepth', 1, ...
            'LookUnderMasks', 'all', 'block_type', 'sysgen');
    catch me
        sg_blk = '';
    end
    
    if length(sg_blk) ~= 1
        error(message('hdlcoder:hdlcoderdemos:sysgenblk', sys));
    else
        sg_blk = char(sg_blk);
        sg_sys = sys;
    end
end

%--------------------------------------------------------------------------       
function [mdldir strdir] = getSysGenDir(blk)

xsgdir = xlgetparam(blk, 'directory');

top = hdlgettoplevel(blk);
mdldir = ['mdldir = fileparts(get_param(''' top ''',''FileName''));\n'];
strdir = 'fullfile(mdldir,xsgdir)';

if length(xsgdir) > 1
    if strcmp('//', xsgdir(1:2)) || strcmp(':', xsgdir(2))
        % xsgdir is full path
        mdldir = '';
        strdir = 'xsgdir';
    end
end
