%% $RCSfile: fixptmatrixmul.tlc,v $
%% $Revision: 1.2.4.5 $
%% $Date: 2004/10/06 13:26:36 $
%%
%% This file contains tlc code for generation of fixed point multiplication
%%
%% Copyright 1994-2003 The MathWorks, Inc.
%%

%% Function: FixPt_MatrixMultiply ==========================================
%%
%function FixPt_MatrixMultiply(cLabelAdr,cDT,aLabelAdr,aDT,bLabelAdr,bDT,roundMode,satMode,nOutRow,nOutCol,nMiddleDim) Output
  %%
  %if ISEQUAL(nOutRow,1.0) && ISEQUAL(nOutCol,1.0)
    %%
    %% optimize dot product case
    %%
    %assign cLabel = "(*(%<cLabelAdr>))"
    %<FixPt_DotProduct(cLabel,cDT,aLabelAdr,aDT,bLabelAdr,bDT,roundMode,satMode,nMiddleDim)>\
    %%
    %return
  %endif
  %%
  %assign scalingAnalysis = FixPt_MultiplyHasMismatchedScaling(cDT,aDT,bDT)
  %%
  %copyrecord cTempDT cDT
  %copyrecord aTempDT aDT
  %copyrecord bTempDT bDT
  %%
  %assign useUtilityFunction = TLC_TRUE
  %assign codeBodyNeeded     = TLC_TRUE
  %%
  %if scalingAnalysis.MismatchedScaling 
     %%
     %% Mismatched scaling has too many instance specific details for a function
     %%   so just inline code
     %%
     %assign useUtilityFunction = TLC_FALSE
     %%
  %else
     %%
     %assign ExPrec = aTempDT.FixedExp + bTempDT.FixedExp - cTempDT.FixedExp
     %%
     %assign cTempDT.FracSlope = 1.0
     %assign aTempDT.FracSlope = 1.0
     %assign bTempDT.FracSlope = 1.0
     %%
     %assign cTempDT.FixedExp = 0
     %assign aTempDT.FixedExp = ExPrec  - scalingAnalysis.FixExpAdjustment
     %assign bTempDT.FixedExp = 0
  %endif  
  %%
  %% XXX
  %% Should optimize cases that don't need saturation
  %% For example a DSP with accumulator gaurd bits
  %%
  %% determine amount of left shifting or right shifting if any
  %%
  %assign ExPrec = aTempDT.FixedExp + bTempDT.FixedExp - cTempDT.FixedExp
  %%
  %if useUtilityFunction
    %%
    %if fxpIsDataTypeFloatOrSclDbl(cTempDT)
      %%
      %% output is floating point so 
      %%    rounding and saturation doesn't matter
      %%
      %assign roundMode = "Floor"
      %assign satMode   = "Wrap"
      %%
    %elseif ExPrec >= 0 && ...
            !fxpIsDataTypeFloatOrSclDbl(aTempDT) && ...
            !fxpIsDataTypeFloatOrSclDbl(bTempDT)
      %%
      %% no shifts right so NEVER round
      %%
      %assign roundMode = "Floor"
      %%
    %elseif roundMode == "Zero" && ...
            FixPt_DataTypeIsUnsignedFixPt(aTempDT) && ...
            FixPt_DataTypeIsUnsignedFixPt(bTempDT)
      %%
      %% both Unsigned so ZERO like FLOOR
      %%
      %assign roundMode = "Floor"
      %%
    %endif
    %%
    %% Create a string to represent the utility
    %%
    %assign utilityName = FixPt_UtilityMakeName("MatrixMultiply")
    %%
    %% identify current INPUT storage type
    %%
    %assign utilityName = FixPt_UtilityNameAppendDT(utilityName,cTempDT)
    %assign utilityName = FixPt_UtilityNameAppendDT(utilityName,aTempDT)
    %assign utilityName = FixPt_UtilityNameAppendDT(utilityName,bTempDT)
    %%
    %% identify amount of left shifting or right shifting if any
    %%
    %if ExPrec < 0
      %assign utilityName = utilityName + "_SR"
      %assign utilityName = utilityName + STRING(-ExPrec)
    %elseif ExPrec > 0
      %assign utilityName = utilityName + "_SL"
      %assign utilityName = utilityName + STRING(ExPrec)
    %endif
    %%
    %assign utilityName = FixPt_UtilityNameAppendMode(utilityName,roundMode,satMode)
    %%
    %% END: Create a string to represent the  utility
    %%
    %% create the call to the utility
    %%
    %<utilityName>(%<cLabelAdr>,%<aLabelAdr>,%<bLabelAdr>,%<nOutRow>,%<nOutCol>,%<nMiddleDim>);
    %%
    %% determine if the required utility has already been defined
    %%   it has then not need to recreate create the definition.
    %%
    %assign codeBodyNeeded = !(ISFIELD(FixPtUtils,utilityName))
    %%
  %endif  
  %%
  %if codeBodyNeeded
    %%
    %if useUtilityFunction
      %%
      %assign inline_extension  = ""
      %assign nOutRowLabel      = "nOutRow"
      %assign nOutColLabel      = "nOutCol"
      %assign nMiddleDimLabel   = "nMiddleDim"
    %else
      %assign inline_extension  = "_MatrixMultiplyUtil"
      %assign nOutRowLabel      = "%<nOutRow>"
      %assign nOutColLabel      = "%<nOutCol>"
      %assign nMiddleDimLabel   = "%<nMiddleDim>"
    %endif
    %%
    %assign curProductLabel = "curProduct"
    %%
    %assign pOutLabel           = "pOut"       + inline_extension
    %assign pIn1Label           = "pIn1"       + inline_extension
    %assign pIn2Label           = "pIn2"       + inline_extension
    %assign outLinearIndexLabel = "iOutLinear" + inline_extension
    %assign outRowIndexLabel    = "iOutRow"    + inline_extension
    %assign outColIndexLabel    = "iOutCol"    + inline_extension
    %assign midDimIndexLabel    = "iMiddleDim" + inline_extension
    %assign in1IndexLabel       = "iIn1"       + inline_extension
    %assign in2IndexLabel       = "iIn2"       + inline_extension
    %%
    %if useUtilityFunction
      %%
      %<LibPushEmptyStackSharedUtils()>\
      %%
      %% register that utility is being defined
      %%
      %assign tmpRet = SETFIELD(FixPtUtils,utilityName,1)
      %%
      %openfile utilityHeaderComment
      
      /*********************************************************************
      * Matrix Multiply Utility %<utilityName>
      */
      %closefile utilityHeaderComment
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      %% open a buffer to hold the utility definition
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      %%
      
      %openfile funcProto
      void %<utilityName>(%<cTempDT.NativeType> *%<pOutLabel>, const %<aTempDT.NativeType> *%<pIn1Label>, const %<bTempDT.NativeType> *%<pIn2Label>, %<FixPt_int_label> %<nOutRowLabel>, %<FixPt_int_label> %<nOutColLabel>, %<FixPt_int_label> %<nMiddleDimLabel>);
      %closefile funcProto
      %openfile utilityDef
      void %<utilityName>(%<cTempDT.NativeType> *%<pOutLabel>, const %<aTempDT.NativeType> *%<pIn1Label>, const %<bTempDT.NativeType> *%<pIn2Label>, %<FixPt_int_label> %<nOutRowLabel>, %<FixPt_int_label> %<nOutColLabel>, %<FixPt_int_label> %<nMiddleDimLabel>)
      {
    %else
      {
        /* Matrix Multiply Operation that has been inlined to handle mismatched scaling
         */
      %<cTempDT.NativeType> *%<pOutLabel> = %<cLabelAdr>;
      const %<aTempDT.NativeType> *%<pIn1Label> = %<aLabelAdr>;
      const %<bTempDT.NativeType> *%<pIn2Label> = %<bLabelAdr>;
    %endif
      %<FixPt_int_label> %<outLinearIndexLabel> = 0;
      %<FixPt_int_label> %<outRowIndexLabel>;
      %<FixPt_int_label> %<outColIndexLabel>;
      %<FixPt_int_label> %<midDimIndexLabel>;
      %<FixPt_int_label> %<in1IndexLabel>;
      %<FixPt_int_label> %<in2IndexLabel>;
      %<cTempDT.NativeType> %<curProductLabel>;
      for(%<outColIndexLabel> = 0; %<outColIndexLabel> < (%<nOutColLabel>); %<outColIndexLabel>++)
      {
        for (%<outRowIndexLabel> = 0; %<outRowIndexLabel> < (%<nOutRowLabel>); %<outRowIndexLabel>++)
        {
          %assign OutLabelCur = "%<pOutLabel>[%<outLinearIndexLabel>]"
          %assign initValue = FixPt_Dbl2StoredInt(0.0,cTempDT)
          %%
          %<OutLabelCur> = %<initValue>;
          %%
          %<in1IndexLabel> = %<outRowIndexLabel>;
          %<in2IndexLabel> = %<outColIndexLabel> * (%<nMiddleDimLabel>);
          for(%<midDimIndexLabel> = 0; %<midDimIndexLabel> < (%<nMiddleDimLabel>); %<midDimIndexLabel>++)
          {
            %assign In1Label = "%<pIn1Label>[%<in1IndexLabel>]"
            %assign In2Label = "%<pIn2Label>[%<in2IndexLabel>]"
            %<FixPt_Multiply(curProductLabel, cTempDT, In1Label, aTempDT, In2Label, bTempDT, roundMode, satMode)>\
            %<FixPt_Accumulate_Easy(OutLabelCur,cTempDT,curProductLabel,cTempDT,roundMode,satMode,1)>\
            %<in1IndexLabel> += (%<nOutRowLabel>);
            %<in2IndexLabel>++;
          }
          %<outLinearIndexLabel>++;
        }
      }
    }
    %if useUtilityFunction
      %%
      %closefile utilityDef
      %%
      %openfile utilityTrailerComment
    
      /* end %<utilityName>
      *********************************************************************/
      %closefile utilityTrailerComment
      %%
      %assign utilityDef = utilityHeaderComment + utilityDef + utilityTrailerComment
      %%
      %<SLibDumpUtilsSourceCode(utilityName,funcProto,utilityDef)>\
      %<LibCacheFunctionPrototype(funcProto)>\
      %%
      %assign GSUStackBuf = LibPopStackSharedUtilsIncludes()
    %endif
  %endif
%endfunction %% FixPt_MatrixMultiply

%function FixPt_MatrixMultiplyHetrogenous(cLabelAdr,cDT,aLabelAdr,aDT,bLabelAdr,bDT,roundMode,satMode,yM,yN,uM,Multiplication,FixPtGainID) Output
    %%
    %assign tempOutLabel = "tempOut"
    {
      %assign index = 0
      %<cDT.NativeType> %<tempOutLabel>;
      %foreach jj = yN
        %foreach ii = yM
          %assign OutLabelCur = "(%<cLabelAdr>)[%<jj * yM + ii>]"
          %%
          %assign initValue = FixPt_Dbl2StoredInt(0.0,cDT)
          %%
          %<OutLabelCur> = %<initValue>;
          %%
          %foreach kk = uM
            %assign In1Label = "(%<aLabelAdr>)[%<kk * yM + ii>]"
            %assign In2Label = "(%<bLabelAdr>)[%<jj * uM + kk>]"
            %% In1 matrix has hertro ids
            %if Multiplication == "K*u"
              %assign aDT = FixPt_GetParameterDataType(FixPtGainID, ii, kk)
            %else
              %assign bDT = FixPt_GetParameterDataType(FixPtGainID, kk, jj)
            %endif
            %<FixPt_Multiply(tempOutLabel, cDT, In1Label, aDT, In2Label, bDT, roundMode, satMode)>\
            %<FixPt_Accumulate(OutLabelCur,cDT,tempOutLabel,cDT,satMode,1)>\
          %endforeach
        %endforeach
      %endforeach
    }
%endfunction

%function FixPt_MultiplyHasMismatchedScaling(cDT,aDT,bDT) void
  %%
  %createrecord results { ...
        MismatchedScaling    TLC_FALSE; ...
        NonUnityFracSlope    TLC_FALSE; ...
        FixExpAdjustment     0          ...
      }
  %%
  %% if any of the signals has a non-zero bias 
  %% then regard as mismatch TRUE
  %%
  %if !ISEQUAL(aDT.Bias,0.0) || ...
      !ISEQUAL(bDT.Bias,0.0) || ...
      !ISEQUAL(cDT.Bias,0.0)
    %%
    %assign results.MismatchedScaling = TLC_TRUE
    %%
  %else
    %% 
    %% If the FracSlope are all trivial
    %%   the leave the results at default
    %% otherwise closer analysis is required
    %%
    %if !ISEQUAL(aDT.FracSlope,1.0) || ...
        !ISEQUAL(bDT.FracSlope,1.0) || ...
        !ISEQUAL(cDT.FracSlope,1.0)
      %%
      %assign results.NonUnityFracSlope = TLC_TRUE
      %%
      %assign fracCorrection = cDT.FracSlope /( aDT.FracSlope * bDT.FracSlope )
      %%
      %if fxpIsDataTypeFloatOrSclDbl(cDT)
        %%
        %if ISEQUAL(fracCorrection,1.0)
          %%
          %assign results.FixExpAdjustment = CAST("Number", 0)
          %%
        %elseif ISEQUAL(fracCorrection,2.0)
          %%
          %assign results.FixExpAdjustment = CAST("Number", 1)
          %%
        %elseif ISEQUAL(fracCorrection,0.5)
          %%
          %assign results.FixExpAdjustment = CAST("Number",-1)
          %%
        %elseif ISEQUAL(fracCorrection,0.25)
          %%
          %assign results.FixExpAdjustment = CAST("Number",-2)
          %%
        %else
          %%
          %assign results.MismatchedScaling = TLC_TRUE
          %%
        %endif
      %else
        %%
        %assign slopeFixExp = FEVAL("fixptPrivate",...
                                    "fhpBestPrecisionQuantizeParts",...
                                    fracCorrection,...
                                    cDT.RequiredBits,...
                                    cDT.IsSigned)
        %%
        %assign slope  = CAST("Real",slopeFixExp[0])
        %%
        %if ISEQUAL(slope,1.0)
          %%
          %assign results.FixExpAdjustment = CAST("Number",slopeFixExp[1])
          %%
        %else
          %%
          %assign results.MismatchedScaling = TLC_TRUE
          %%
        %endif
      %endif
      %%
    %endif
  %endif
  %%
  %return results
  %%
%endfunction


%function FixPt_ComplexMatrixMultiplyHetrogenous(cLabelAdr,cDT,aLabelAdr,aDT,bLabelAdr,bDT,roundMode,satMode,yM,yN,uM,In1IsComplex,In2IsComplex,Multiplication,FixPtGainID) Output
    %%
    %%
    %assign tempOutLabel = "tempOut"
    %assign cPrefix = "c"
    %assign cDTLabel = "%<cPrefix>%<cDT.NativeType>"
    %assign tempOutLabelRe = "tempOut.re"
    %assign tempOutLabelIm = "tempOut.im"
    %assign tempOutLabel   = "tempOut"
    %assign tmp1Label = "yTemp1"
    {
      %assign index = 0
      %<cDTLabel> %<tempOutLabel>;
      %if In1IsComplex && In2IsComplex
        %<cDT.NativeType> %<tmp1Label>;
      %endif
      %foreach jj = yN
        %foreach ii = yM
          %assign OutLabelCurRe = "(%<cLabelAdr>)[%<jj * yM + ii>].re"
          %assign OutLabelCurIm = "(%<cLabelAdr>)[%<jj * yM + ii>].im"
          %%
          %assign initValue = FixPt_Dbl2StoredInt(0.0,cDT)
          %%
          %<OutLabelCurRe> = %<initValue>;
          %<OutLabelCurIm> = %<initValue>;
          %%
          %foreach kk = uM
            %assign In1LabelRe = "(%<aLabelAdr>)[%<kk * yM + ii>].re"
            %assign In1LabelIm = "(%<aLabelAdr>)[%<kk * yM + ii>].im"
            %assign In2LabelRe = "(%<bLabelAdr>)[%<jj * uM + kk>].re"
            %assign In2LabelIm = "(%<bLabelAdr>)[%<jj * uM + kk>].im"
            %if Multiplication == "K*u"
              %% Then In1 matrix has hertro ids
              %assign aDT = FixPt_GetParameterDataType(FixPtGainID, ii, kk)
            %else
              %% In2 matrix has hetrogenous ids
              %assign bDT = FixPt_GetParameterDataType(FixPtGainID, kk, jj)
            %endif
            %if In1IsComplex && In2IsComplex
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_Multiply(tmp1Label,cDT,...
                In1LabelIm,aDT,...
                In2LabelIm,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_AccumNeg(tempOutLabelRe,cDT,...
                tmp1Label,cDT,...
                FixPtSaturationMode)>\
              %%
              %<FixPt_Multiply(tempOutLabelIm,cDT,...
                In1LabelRe,aDT,...
                In2LabelIm,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_Multiply(tmp1Label,cDT,...
                In1LabelIm,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_AccumPos(tempOutLabelIm,cDT,...
                tmp1Label,cDT,...
                FixPtSaturationMode)>\
            %elseif !In1IsComplex && In2IsComplex
              %assign In1LabelRe = "(%<aLabelAdr>)[%<kk * yM + ii>]"
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %%
              %<FixPt_Multiply(tempOutLabelIm,cDT,...
                In1LabelRe,aDT,...
                In2LabelIm,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
            %elseif In1IsComplex && !In2IsComplex
              %assign In2LabelRe = "(%<bLabelAdr>)[%<jj * uM + kk>]"
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %%
              %<FixPt_Multiply(tempOutLabelIm,cDT,...
                In1LabelIm,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
            %elseif !In1IsComplex && !In2IsComplex
            %%START_ASSERT
	      %assign In1LabelRe = "(%<aLabelAdr>)[%<kk * yM + ii>]"
              %assign In2LabelRe = "(%<bLabelAdr>)[%<jj * uM + kk>]"
              tempOut.im = 0;
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
            %%END_ASSERT
	    %endif
            %<FixPt_Accumulate(OutLabelCurRe,cDT,tempOutLabelRe,cDT,satMode,1)>\
            %<FixPt_Accumulate(OutLabelCurIm,cDT,tempOutLabelIm,cDT,satMode,1)>\
          %endforeach
        %endforeach
      %endforeach
    }
%endfunction


%% Function: FixPt_ComplexMatrixMultiply ==========================================
%%
%function FixPt_ComplexMatrixMultiply(cLabelAdr,cDT,aLabelAdr,aDT,bLabelAdr,bDT,roundMode,satMode,yM,yN,uM,In1IsComplex,In2IsComplex) Output
  %%
  %% Create a string to represent the utility
  %%
  %assign utilityName = FixPt_UtilityMakeName("MatrixMultiply_Complex")
  %if !In1IsComplex && !In2IsComplex
      %assign utilityName = utilityName + "RealReal"
  %elseif In1IsComplex && !In2IsComplex
    %assign utilityName = utilityName + "ComplexReal"
  %elseif !In1IsComplex && In2IsComplex
    %assign utilityName = utilityName + "RealComplex"
  %endif
  %%
  %assign utilityName = FixPt_UtilityNameAppendDT(utilityName,cDT)
  %assign utilityName = FixPt_UtilityNameAppendDT(utilityName,aDT)
  %assign utilityName = FixPt_UtilityNameAppendDT(utilityName,bDT)
  %%
  %% identify amount of left shifting or right shifting
  %% if any
  %%
  %assign ExPrec = aDT.FixedExp + bDT.FixedExp - cDT.FixedExp
  %if ExPrec < 0
    %assign utilityName = utilityName + "_SR"
    %assign utilityName = utilityName + STRING(-ExPrec)
  %elseif ExPrec > 0
    %assign utilityName = utilityName + "_SL"
    %assign utilityName = utilityName + STRING(ExPrec)
  %endif
  %%
  %% XXX
  %% Should optimize cases that don't need saturation
  %% For example a DSP with accumulator gaurd bits
  %%
  %if fxpIsDataTypeFloatOrSclDbl(cDT)
    %%
    %% output is floating point so 
    %%    rounding and saturation doesn't matter
    %%
    %assign roundMode = "Floor"
    %assign satMode   = "Wrap"
    %%
  %elseif ExPrec >= 0 && ...
          !fxpIsDataTypeFloatOrSclDbl(aDT) && ...
          !fxpIsDataTypeFloatOrSclDbl(bDT)
    %%
    %% no shifts right so NEVER round
    %%
    %assign roundMode = "Floor"
    %%
  %elseif roundMode == "Zero" && ...
          FixPt_DataTypeIsUnsignedFixPt(aDT) && ...
          FixPt_DataTypeIsUnsignedFixPt(bDT)
    %%
    %% both Unsigned so ZERO like FLOOR
    %%
    %assign roundMode = "Floor"
    %%
  %endif
  %%
  %assign utilityName = FixPt_UtilityNameAppendMode(utilityName,roundMode,satMode)
  %%
  %% END: Create a string to represent the search utility
  %%
  %% create the call of the function
  %%
  %<utilityName>(%<cLabelAdr>,%<aLabelAdr>,%<bLabelAdr>,%<yM>,%<yN>,%<uM>);
  %%
  %% determine if the required utility has already been defined
  %%   If it has not, then create the definition.
  %%
  %if !(ISFIELD(FixPtUtils,utilityName))
    %%
    %<LibPushEmptyStackSharedUtils()>\
    %%
    %assign pYLabel = "pOutputMatrixMultiplyUtil"
    %%
    %% register that utility is being defined
    %%
    %assign tmpRet = SETFIELD(FixPtUtils,utilityName,1)
    %%
    %% open a buffer to hold the utility header comments
    %%
    %openfile utilityHeaderComment

    /*********************************************************************
    * Complex Matrix Multiply Utility %<utilityName>
    */
    %closefile utilityHeaderComment
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% open a buffer to hold the utility definition
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %openfile utilityDef
    %%
    %assign cPrefix = "c"
    %if In1IsComplex
      %assign aDTLabel = "%<cPrefix>%<aDT.NativeType>"
    %else
        %assign aDTLabel = "%<aDT.NativeType>"
    %endif
    %if In2IsComplex
      %assign bDTLabel = "%<cPrefix>%<bDT.NativeType>"
    %else
      %assign bDTLabel = "%<bDT.NativeType>"
    %endif
    %assign cDTLabel = "%<cPrefix>%<cDT.NativeType>"
    %openfile funcProto
    void %<utilityName>(%<cDTLabel> *%<pYLabel>, const %<aDTLabel> *pIn1, const %<bDTLabel> *pIn2, %<FixPt_int_label> yM, %<FixPt_int_label> yN, %<FixPt_int_label> uM);
    %closefile funcProto
    %selectfile utilityDef
    void %<utilityName>(%<cDTLabel> *%<pYLabel>, const %<aDTLabel> *pIn1, const %<bDTLabel> *pIn2, %<FixPt_int_label> yM, %<FixPt_int_label> yN, %<FixPt_int_label> uM)
    %assign tempOutLabelRe = "tempOut.re"
    %assign tempOutLabelIm = "tempOut.im"
    %assign tempOutLabel   = "tempOut"
    %assign tmp1Label = "yTemp1"
    {
      %<FixPt_int_label> locindex = 0;
      %<FixPt_int_label> i, j , k;
      %<FixPt_int_label> iIn1, iIn2;
      %<cDTLabel> %<tempOutLabel>;
      %if In1IsComplex && In2IsComplex
        %<cDT.NativeType> %<tmp1Label>;
      %endif
      for(j =0; j < (yN); j++)
      {
        for (i = 0; i < (yM); i++)
        {
          iIn1 = i;
          iIn2 = j * (uM);
          %assign OutLabelCurRe = "%<pYLabel>[locindex].re"
          %assign OutLabelCurIm = "%<pYLabel>[locindex].im"
          %%
          %assign initValue = FixPt_Dbl2StoredInt(0.0,cDT)
          %%
          %<OutLabelCurRe> = %<initValue>;
          %<OutLabelCurIm> = %<initValue>;
          %%
          for(k = 0; k < (uM); k++)
          {
            %if In1IsComplex && In2IsComplex
              %assign In1LabelRe = "pIn1[iIn1].re"
              %assign In1LabelIm = "pIn1[iIn1].im"
              %assign In2LabelRe = "pIn2[iIn2].re"
              %assign In2LabelIm = "pIn2[iIn2].im"
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_Multiply(tmp1Label,cDT,...
                In1LabelIm,aDT,...
                In2LabelIm,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_AccumNeg(tempOutLabelRe,cDT,...
                tmp1Label,cDT,...
                FixPtSaturationMode)>\
              %%
              %<FixPt_Multiply(tempOutLabelIm,cDT,...
                In1LabelRe,aDT,...
                In2LabelIm,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_Multiply(tmp1Label,cDT,...
                In1LabelIm,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %<FixPt_AccumPos(tempOutLabelIm,cDT,...
                tmp1Label,cDT,...
                FixPtSaturationMode)>\
            %elseif !In1IsComplex && In2IsComplex
              %assign In1LabelRe = "pIn1[iIn1]"
              %assign In2LabelRe = "pIn2[iIn2].re"
              %assign In2LabelIm = "pIn2[iIn2].im"
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %%
              %<FixPt_Multiply(tempOutLabelIm,cDT,...
                In1LabelRe,aDT,...
                In2LabelIm,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
            %elseif In1IsComplex && !In2IsComplex
              %assign In1LabelRe = "pIn1[iIn1].re"
              %assign In1LabelIm = "pIn1[iIn1].im"
              %assign In2LabelRe = "pIn2[iIn2]"
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
              %%
              %<FixPt_Multiply(tempOutLabelIm,cDT,...
                In1LabelIm,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
            %elseif !In1IsComplex && !In2IsComplex
            %%START_ASSERT  
	      %assign In1LabelRe = "pIn1[iIn1]"
              %assign In2LabelRe = "pIn2[iIn2]"
              tempOut.im = 0;
              %<FixPt_Multiply(tempOutLabelRe,cDT,...
                In1LabelRe,aDT,...
                In2LabelRe,bDT,...
                FixPtRoundingMode,FixPtSaturationMode)>\
            %%END_ASSERT
	    %endif
            %<FixPt_Accumulate(OutLabelCurRe,cDT,tempOutLabelRe,cDT,satMode,1)>\
            %<FixPt_Accumulate(OutLabelCurIm,cDT,tempOutLabelIm,cDT,satMode,1)>\
            iIn1 += (yM);
            iIn2++;
          }
          locindex++;
        }
      }
    }
    %closefile utilityDef
    %%
    %openfile utilityTrailerComment
    
    /* end %<FixPtUtilType> %<utilityName>
    *********************************************************************/
    %closefile utilityTrailerComment
    %%
    %% cause utility define to be included in generated code
    %%
    %assign utilityDef = utilityHeaderComment + utilityDef + utilityTrailerComment
    %%
    %<SLibDumpUtilsSourceCode(utilityName,funcProto,utilityDef)>\
    %<LibCacheFunctionPrototype(funcProto)>\
    %%
    %assign GSUStackBuf = LibPopStackSharedUtilsIncludes()
  %endif
%endfunction
