blob: 69941b40168c8ee59999e11020e2f010a4fa1031 [file] [log] [blame]
#!/usr/bin/perl
#
# Copyright Statement:
# --------------------
# This software is protected by Copyright and the information contained
# herein is confidential. The software may not be copied and the information
# contained herein may not be used or disclosed except with the written
# permission of MediaTek Inc. (C) 2006
#
# BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
# NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
# SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
#
# BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
# LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
#
# THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
# WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
# LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
# RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
# THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
#
#*****************************************************************************
#*
#* Filename:
#* ---------
#* ldsFrame.pm
#*
#* Project:
#* --------
#*
#*
#* Description:
#* ------------
#* This script is to generate the frame of memory layout
#* and provides the flow of generation
#*
#* Author:
#* -------
#* Carl Kao (mtk08237)
#*
#****************************************************************************/
#****************************************************************************
# Included Modules
#****************************************************************************
use strict;
BEGIN { push @INC, './tools/' } # add additional library path
use ldsInfo;
use CommonUtility;
use sysGenUtility;
package ldsFrame;
#****************************************************************************
# oo >>> Finished
#****************************************************************************
return 1;
#****************************************************************************
# ldsFrame Version
#****************************************************************************
sub ldsFrame_verno
{
return " u0.05";
# u0.05, 2016/06/21 by Tero, Fixed Memory parsing
# u0.04, 2016/01/19 by Tero, Fixed ASSERT multiple parenthesis issue
# u0.03, 2015/10/19 by Carl, Catch invalid input section
# u0.02, 2014/12/17 by Carl, Support multiple overlap section
# u0.01, 2014/02/20 by BM, Initial version
# m0.28 , 20130913 by mei, Fix symbol bug
# m0.27 , 20130605 by mei, Make input section file name more flexible in OVERLAY section
# m0.26 , 20130115 by mei, Change Default csv name to Default.csv
# m0.25 , 20130114 by mei, Set LDSType to be MAIN by default
# m0.24 , 20130113 by mei, Support template getting from build folder first
# m0.23 , 20121030 by mei, Support more flexible ASSERT in Action,
# Support EndAction (to put Action in the end)
# m0.22 , 20121029 by mei, Support MEMORY without counting reserved region
# m0.21 , 20121020 by mei, Make addresses in OVERLAY region be 4 bytes aligned
# m0.20 , 20121002 by mei, Make all lengths are 4 bytes aligned for region-init
# m0.19 , 20120827 by mei, Support Head input sections
# m0.18 , 20120817 by mei, Support SetMemorySetting() without calling callback if no need to replace
# m0.17 , 20120816 by mei, Change symbol assignment in OVERLAY to fix ld's bug
# m0.16 , 20120816 by mei, Support Input section with Common Block, Chip Block and DefaultChip Block
# m0.15 , 20120727 by mei, Refine lds output format
# m0.14 , 20120724 by mei, Support MaxSize ASSERT
# m0.13 , 20120713 by mei, Support atomic Type(e.g. not accept //SectionFrame)
# Fix LoadAddress' bug
# Support Default address(top and bottom) align 4 bytes
# m0.12 , 20120712 by mei, Remove EWS since no need to add dependency in pm file
# m0.11 , 20120710 by mei, Support input section got from chip.txt as well
# m0.10 , 20120702 by mei, Support EWS
# m0.09 , 20120702 by mei, Support Memory Setting with booting type via GetBootingType()
# m0.08 , 20120625 by mei, Use scalar instead of $#
# m0.07 , 20120615 by mei, Support using $# on Linux
# m0.06 , 20120530 by mei, Support RegionList by chip
# m0.05 , 20120530 by mei, Fix CleanCallBackFunc()'s bug
# m0.04 , 20120528 by mei, Support path and filename case sensitive on Linux
# m0.03 , 20120513 by mei, Support BLldsGen
# m0.02 , 20120507 by mei, Fix ACTION behavior
# m0.01 , 20120507 by mei, initial version
}
#****************************************************************************
# Constants
#****************************************************************************
#****************************************************************************
# Global Variables
#****************************************************************************
my %Func = ("CollectMemorySetting" => undef,
"SetMemorySegment" => undef, # not necessary
"GetChip" => undef,
"SetRegionList" => undef,
"GetBootingType" => undef,
"GetCustomFolder" => undef, # to get CustomFolder's template first
);
my %g_MEMORYSetting;
my $g_nLDSType = 0; #default be MAIN
#****************************************************************************
# Input Parameters
#****************************************************************************
use constant BASIC => 0;
use constant MEMORY => 1;
use constant InputSections => 2;
use constant RegionList => 3;
#LDS Type
use constant MAIN => 0;
use constant BL => 1;
use constant EXT_BL => 2;
use constant FOTA => 3;
#Input Section File Name
use constant COMMON_InputSection => "Common";
use constant ChipDependent_Default_InputSection => "DefaultChip";
use constant HEAD_InputSection => "Head";
#****************************************************************************
# subroutines
#****************************************************************************
sub GetLDSType
{
my %LDSFolderName = (0 => "lds_config",
1 => "BL_lds_config",
2 => "EXT_BL_lds_config",
);
&ldsFrame_die("unsupport LDSType: $g_nLDSType \n", __FILE__, __LINE__) if(!exists $LDSFolderName{$g_nLDSType});
return $LDSFolderName{$g_nLDSType};
}
#ldsFrame::GetPath("MT6280", ldsFrame::MEMORY)
#ldsFrame::GetPath("ROM", ldsFrame::InputSections)
#ldsFrame::GetPath("MT6280", ldsFrame::RegionList)
sub GetPath
{
my ($strKey, $nType) = @_;
my $strPath = undef;
my $LDSFolderName = &GetLDSType();
my $strDefaultSystemFolder = "./custom/system";
my $strTemplateFolder = "$strDefaultSystemFolder/Template/$LDSFolderName/";
my %PathMap = ("ldsMainFrame" => "ldsTemplate/ldsMainFrame.txt",
"RegionList" => "RegionConfig/",
"MEMORY" => "ldsTemplate/MEMORY/",
"InputSections" => "InputSections/",
);
if($nType == BASIC)
{
$strPath = $strTemplateFolder . $PathMap{$strKey};
}
elsif($nType == MEMORY)
{
$strPath = $strTemplateFolder.$PathMap{MEMORY}.$strKey."_".&{$Func{GetBootingType}}().".txt" if(defined $Func{GetBootingType});
$strPath = $strTemplateFolder.$PathMap{MEMORY}.$strKey.".txt" if(!-e $strPath);;
}
elsif($nType == RegionList)
{
$strPath = $strTemplateFolder.$PathMap{RegionList}.$strKey.".csv";
$strPath = $strTemplateFolder.$PathMap{RegionList}."Default.csv" if(!-e $strPath);
$strPath = $strTemplateFolder.$PathMap{RegionList}."RegionList.csv" if(!-e $strPath); # for backward compatible
}
elsif($nType == InputSections)
{
$strPath = $strTemplateFolder . $PathMap{InputSections}.$strKey."/";
}
else
{
&ldsFrame_die("[GetPath]Unsupport Type", __FILE__, __LINE__);
}
if(exists $Func{GetCustomFolder})
{
my $strCustomedFolder = &{$Func{GetCustomFolder}}();
my $strCustomedPath = $strPath;
$strCustomedPath =~ s/$strDefaultSystemFolder/$strCustomedFolder/;
$strPath = $strCustomedPath if(-e $strCustomedPath);
}
return $strPath;
}
#****************************************************************************
# subroutine: ProcessTemplate
# Input: $strFilePath: the file to be processed
# $strKeyFinding: e.g. ldsGen or AUTOGEN
# Output: $content: the content after processing
# Description: if there is the pattern as [ldsGen_funcname],
# the whole pattern will be replaced by calling funcname().
# if funcname() doesn't exist, it'll fail and report error.
#****************************************************************************
sub ProcessTemplate
{
my ($strFilePath, $strKeyFinding) = @_;
my $content;
open (FILE_HANDLE, $strFilePath) or &ldsFrame_die("Cannot open $strFilePath\n", __FILE__, __LINE__);
while(<FILE_HANDLE>)
{
my $strLine = $_;
while ($strLine =~ /\[$strKeyFinding\_(\w+)\]/)
{
my $func = $1;
my $template;
{
no strict 'refs';
$template = &{$func}() if(exists &{$func})
or &ldsFrame_die("$func() doesn't exist!\n", __FILE__, __LINE__);
}
chomp($strLine);
$strLine =~ s/\[$strKeyFinding\_$func\]/$template/g;
}
$content .= $strLine;
}
close FILE_HANDLE;
return $content;
}
sub ProcessSection
{
my ($strContent, $Info_ref, $Index_ref) = @_;
my @lines = split(/\n/, $strContent);
my $strResult;
foreach my $strLine (@lines)
{
while ($strLine =~ /\[ldsGen_(\w+)\]/)
{
my $func = "Gen".$1;
my $template;
{
no strict 'refs';
$template = &{$func}($Info_ref, $Index_ref) if(exists &{$func})
or &ldsFrame_die("[ProcessSection]$func() doesn't exist!\n", __FILE__, __LINE__);
}
$strLine =~ s/\[ldsGen_$1\]/$template/g;
}
$strResult .= $strLine . "\n";
}
return $strResult;
}
#****************************************************************************
sub GenLDS
{
($g_nLDSType) = @_;
#Check CallBack functions
my $strLayout = &ProcessTemplate( &GetPath("ldsMainFrame", BASIC) , "ldsGen");
return $strLayout;
}
sub CleanCallBackFunc
{
foreach (keys %Func)
{
delete $Func{$_};
}
%g_MEMORYSetting = ();
$g_nLDSType = 0;
}
sub SetCallBackFunc
{
my ($strKey, $func) = @_;
$Func{$strKey} = $func;
}
#****************************************************************************
sub GenMEMORY
{
my $MEMORYPath = &GetPath(&{$Func{GetChip}}(), MEMORY);
my $MEMORYContent = &CommonUtil::GetFileContent($MEMORYPath);
my $MEMORY_SEGMENT_aref = &ldsInfo::ParseMEMORY($MEMORYContent);
my ($RegionList_ref, $Index_ref)= &PreProcessRegionList(undef);
&SetMemorySetting($MEMORY_SEGMENT_aref, $MEMORYPath, $RegionList_ref, $Index_ref);
&{$Func{SetMemorySegment}}($MEMORY_SEGMENT_aref) if(exists $Func{SetMemorySegment}); # for extension, not used now
my $strMEMORY;
foreach my $i (@$MEMORY_SEGMENT_aref)
{
if (!defined $i->[1])
{
$strMEMORY .="$i->[0]\n";
next;
}
$strMEMORY .= " $i->[0] : ORIGIN = $i->[1], LENGTH = $i->[2]\n";
my $nBase = eval($i->[1]);
my $nLen = eval($i->[2]);
$g_MEMORYSetting{$i->[0]} = [&CommonUtil::Dec2Hex($nBase),
&CommonUtil::Dec2Hex($nLen)];
}
return $strMEMORY;
}
sub SetMemorySetting
{
my ($MEMORY_SEGMENT_aref, $MEMORYPath, $RegionList_ref, $Index_ref) = @_;
if(exists $Func{CollectMemorySetting})
{
my $Setting = &{$Func{CollectMemorySetting}}($MEMORYPath, , $RegionList_ref, $Index_ref);
foreach my $i (@$MEMORY_SEGMENT_aref)
{
while($i->[1] =~ /\[(\S+)\]/)
{
my $temp = $1;
&ldsFrame_die("$1 in\n$MEMORYPath\n isn't set in CollectMemorySetting()!\n", __FILE__, __LINE__) if(!exists $Setting->{$1});
$i->[1] =~ s/\[$temp\]/$Setting->{$temp}/g;
}
while($i->[2] =~ /\[(\S+)\]/)
{
my $temp = $1;
&ldsFrame_die("$1 in\n$MEMORYPath\n isn't set in CollectMemorySetting()!\n", __FILE__, __LINE__) if(!exists $Setting->{$1});
$i->[2] =~ s/\[$temp\]/$Setting->{$temp}/g;
}
}
}
}
sub PreProcessRegionList
{
my ($MEMORYSetting_href) = @_;
my $RegionListPath = &GetPath(&{$Func{GetChip}}(), RegionList);
my ($BasicRegionList_ref, $Index_ref) = &CommonUtil::ParseCSV($RegionListPath, undef);
my $RegionList_ref = $BasicRegionList_ref;
$RegionList_ref = &{$Func{SetRegionList}}($BasicRegionList_ref, $Index_ref, $MEMORYSetting_href)
if(exists $Func{SetRegionList});
return ($RegionList_ref, $Index_ref);
}
#****************************************************************************
sub GenSECTIONS
{
my $strLayout;
my ($RegionList_ref, $Index_ref) = &PreProcessRegionList(\%g_MEMORYSetting);
&SetHints_Symbols_Nearby_InputSections($RegionList_ref, $Index_ref);
my $LOADADDR_template;
my $LengthSymbol_template;
my $ASSERT_template;
my $End_template;
my $strPreviousType;
my @OVERLAY_items;
my $strOVERLAY_base;
foreach my $item (@$RegionList_ref)
{
my $strType = $item->[$Index_ref->{Type}];
if( $strPreviousType =~ /^OVERLAY$/i and ($strType !~ /^OVERLAY$/i or $strOVERLAY_base ne $item->[$Index_ref->{BaseRegion}]) )
{
my ($template, $strLOADADDR, $strLengthSymbol)= &FillOVERLAYSectionFrame(\@OVERLAY_items, $Index_ref);
$strLayout .=$template;
$LOADADDR_template .= $strLOADADDR;
$LengthSymbol_template .= $strLengthSymbol;
@OVERLAY_items = ();
$strOVERLAY_base = "";
}
if( $strType =~ /^OVERLAY$/i)
{
push @OVERLAY_items, $item;
$strOVERLAY_base = $item->[$Index_ref->{BaseRegion}];
}
elsif( $strType =~ /^SectionFrame$/i)
{
$strLayout .= &ProcessSection(&Gen_TEMPLATE_SECTION(), $item, $Index_ref);
$LOADADDR_template .= &Gen_TEMPLATE_LOADADDR($item, $Index_ref);
$LengthSymbol_template .= &Gen_TEMPLATE_LengthSymbol($item, $Index_ref);
$ASSERT_template .= &Gen_TEMPLATE_ASSERT($item, $Index_ref);
}
elsif($strType =~ /^ACTION$/i or $strType =~ /^ENDACTION$/i)
{
my $CMPLOption = $item->[$Index_ref->{CompileOption}];
my $FeatureOption = $item->[$Index_ref->{Condition}];
my @temp = map{ $_ if(($_ ne $strType) and ($_ ne $CMPLOption) and ($_ ne $FeatureOption)) } @$item;
my $strACTION = &CommonUtil::ConnetString(\@temp, ",", undef);
if($strACTION =~ /^ASSERT/ or $strACTION =~ /^\"\s*ASSERT/)
{
$strACTION =~ s/\"//g;
$strACTION =~ s/\,\s*/\,\"/;
$strACTION =~ s/\)$/\"\)/;
}
$End_template .= " $strACTION\n" if($strType=~/END/i);
$strLayout .= " $strACTION\n" if($strType!~/END/i);
}
elsif($strType =~/^LinkerSymbol$/i)
{
$strLayout .= &FillLinkerSymbol($item, $Index_ref);
}
$strPreviousType = $strType;
}
$strLayout .= $LOADADDR_template . $LengthSymbol_template . $ASSERT_template . $End_template;
return $strLayout;
}
sub AvoidOrphanSECTIONS
{
my $strLayout;
my ($RegionList_ref, $Index_ref) = &PreProcessRegionList(\%g_MEMORYSetting);
&SetHints_Symbols_Nearby_InputSections($RegionList_ref, $Index_ref);
#my $LOADADDR_template;
#my $LengthSymbol_template;
#my $ASSERT_template;
#my $End_template;
my $strPreviousType;
my @OVERLAY_items;
my $strOVERLAY_base;
foreach my $item (@$RegionList_ref)
{
my $strType = $item->[$Index_ref->{Type}];
if( $strPreviousType =~ /^OVERLAY$/i and ($strType !~ /^OVERLAY$/i or $strOVERLAY_base ne $item->[$Index_ref->{BaseRegion}]) )
{
#@OVERLAY_items = ();
$strOVERLAY_base = "";
}
if( $strType =~ /^OVERLAY$/i)
{
#push @OVERLAY_items, $item;
$strOVERLAY_base = $item->[$Index_ref->{BaseRegion}];
my $strName = $item->[$Index_ref->{Name}];
next if ($strName =~ /\.text$|\.rodata$|.data$|\.bss$/);
$strName =~ s/#//g;
$strLayout .= " "x4 ."INVALID_INPUT_SECTION__$strName 0xDEAD0000 : { * ($strName); }\n";
}
elsif( $strType =~ /^SectionFrame$/i)
{
my $strName = $item->[$Index_ref->{Name}];
next if ($strName =~ /\.text$|\.rodata$|.data$|\.bss$|bss$/);
$strName =~ s/#//g;
$strLayout .= " "x4 ."INVALID_INPUT_SECTION__$strName 0xDEAD0000 : { * ($strName); }\n";
}
$strPreviousType = $strType;
}
#$strLayout .= "LONG(0);\n";
$strLayout = " "x4 ."\/\* If build fail with logs in link.log like this \n".
" "x12 ."\"section INVALID_INPUT_SECTION__XX_section_name loaded at [00000000,00000003] overlaps section ROM_GFH loaded at [00000000,000004af]\"\n".
" "x8 ."It means there are wrong input sections \"XX_section_name.\"\n".
" "x8 ."Please use correct input section name by following the rules in mcu/custom/system/Template/lds_config/InputSectionRule.txt\n".
" "x8 ."If you cannot find the symbol, please use \"\.\/m gendummy\" command.\n".
" "x8 ."A dummy sym file will be generated in bin folder. Search the keyword INVALID_INPUT_SECTION to find the symbol\n".
" "x4 ."\*\/\n".
$strLayout if(0);
return $strLayout;
}
sub FillLinkerSymbol #Called by GenSECTIONS()
{
my ($Info_ref, $Index_ref) = @_;
my $template;
my $AttributeIndex = $Index_ref->{Attribute};
my $NameIndex = $Index_ref->{Name};
if($Info_ref->[$AttributeIndex] =~ /(\S+)::(\S+)/)
{
my $strPostfix = $2;
my $strPrefix = $1 =~ /EV/ ? "Image" : "Load";
if($strPostfix =~ /ZIBase/i)
{
$template = 'Image$$' . $Info_ref->[$NameIndex] . '$$ZI$$Base';
}
elsif($strPostfix =~ /ZILength/i)
{
$template = 'Image$$' . $Info_ref->[$NameIndex] . '$$ZI$$Length';
}
elsif($strPostfix =~ /ZILimit/i)
{
$template = 'Image$$' . $Info_ref->[$NameIndex] . '$$ZI$$Limit';
}
elsif($strPostfix =~ /Base/i)
{
$template = $strPrefix . '$$' . $Info_ref->[$NameIndex] . '$$Base';
}
elsif($strPostfix =~ /Length/i)
{
$template = 'Image$$' . $Info_ref->[$NameIndex] . '$$Length';
}
elsif($strPostfix =~ /Limit/i)
{
$template = 'Image$$' . $Info_ref->[$NameIndex] . '$$Limit';
}
my $VMA = $Info_ref->[$Index_ref->{VMA}];
return ' 'x4 . $template . " = $VMA;" . "\n";
}
return "";
}
sub FillOVERLAYSectionFrame #Called by GenSECTIONS()
{
my ($Infos_ref, $Index_ref) = @_;
my ($OVERLAY_template, $strLOADADDR, $strLengthSymbol) = &Gen_TEMPLATE_OVERLAY($Infos_ref, $Index_ref);
my $template = &ProcessSection($OVERLAY_template, $Infos_ref->[0], $Index_ref);
return ($template, $strLOADADDR, $strLengthSymbol);
}
#****************************************************************************
sub GenBaseRegionName # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $strBaseRegion = $Info_ref->[$Index_ref->{BaseRegion}];
my $strOrgRegion = $Info_ref->[$Index_ref->{Name}];
my $strType = $Info_ref->[$Index_ref->{Type}];
my $strName = ($strBaseRegion eq "" or $strType =~ /^OVERLAY$/i) ? $strOrgRegion : $strBaseRegion;
$strName =~ s/\#//g; #workaround because .xxx can't be a folder name or a file name
return $strName;
}
sub GenRegionName # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $strName = $Info_ref->[$Index_ref->{Name}];
$strName =~ s/\#//g; #workaround because .xxx can't be a folder name or a file name
$strName = ".bss" if($strName eq "bss");
return $strName;
}
sub GenVMA # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
return $Info_ref->[$Index_ref->{VMA}];
}
sub GenLMA # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $strLMA = "";
$strLMA = "AT($Info_ref->[$Index_ref->{LMA}])" if($Info_ref->[$Index_ref->{LMA}] ne "");
return $strLMA;
}
sub GenRegionAttr # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $strAttr = "";
$strAttr = "(NOLOAD)" if($Info_ref->[$Index_ref->{Attribute}] eq "ZI");
return $strAttr;
}
sub GenInputSections # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $RegionName = $Info_ref->[$Index_ref->{Name}];
my $InputSectionFolder = &GetPath($RegionName, InputSections);
my $InputSections;
my $SpecificChipPath = $InputSectionFolder.&{$Func{GetChip}}().".txt";
my $DefaultChipPath = $InputSectionFolder.ChipDependent_Default_InputSection.".txt";
my $HeadPath = $InputSectionFolder.HEAD_InputSection.".txt";
if(-e $HeadPath)
{
$InputSections = &CommonUtil::GetFileContent($HeadPath)."\n";
}
if(-e $SpecificChipPath)
{
$InputSections .= &CommonUtil::GetFileContent($SpecificChipPath)."\n";
}
elsif(-e $DefaultChipPath)
{
$InputSections .= &CommonUtil::GetFileContent($DefaultChipPath)."\n";
}
my $CommonPath = $InputSectionFolder.COMMON_InputSection.".txt";
$InputSections .= &CommonUtil::GetFileContent($CommonPath);
return $InputSections;
}
sub GenExecutionRegion # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $ExecutionView = "";
$ExecutionView = " > $Info_ref->[$Index_ref->{ExecutionView}]" if($Info_ref->[$Index_ref->{ExecutionView}] ne "");
return $ExecutionView;
}
sub GenLoadRegion # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $LoadView = "";
$LoadView = " AT> $Info_ref->[$Index_ref->{LoadView}]" if($Info_ref->[$Index_ref->{LoadView}] ne "");
return $LoadView;
}
sub GenALIGN # Called by ProcessSection()
{
my ($Info_ref, $Index_ref) = @_;
my $strALIGN = "";
$strALIGN = "ALIGN(4)" if($Info_ref->[$Index_ref->{Type}] !~ /^OVERLAY$/i);
$strALIGN = $Info_ref->[$Index_ref->{ALIGN}] if($Info_ref->[$Index_ref->{ALIGN}] ne "");
return $strALIGN;
}
#****************************************************************************
sub InsertBasicHintSymbols #used by SetHints_Symbols_Nearby_InputSections
{
my ($RegionList_ref, $Index_ref, $Hints_ref) = @_;
$Index_ref->{Symbols} = keys %$Index_ref;
my $SymbolIndex = $Index_ref->{Symbols};
for(my $i=0; $i < scalar(@$RegionList_ref); $i++)
{
my $item = $RegionList_ref->[$i];
my $strType = $item->[$Index_ref->{Type}];
if( $strType =~ /^SectionFrame$/)
{
my %Symbols = ("Base"=>0, "Limit" =>1, "ZIBase"=>1, "ZILimit"=>1);
$item->[$SymbolIndex] = \%Symbols;
my $BaseRegion = $item->[$Index_ref->{BaseRegion}];
if($BaseRegion ne "")
{
$Hints_ref->{$BaseRegion} = [] if(!exists $Hints_ref->{$BaseRegion});
push(@{$Hints_ref->{$BaseRegion}}, $item);
}
}
}
}
sub SetHints_Symbols_Nearby_InputSections #called by GenSECTIONS()
{
my ($RegionList_ref, $Index_ref) = @_;
my %Hints;
# Step1. insert 4 symbols and collect BaseRegion Info. into %Hints
&InsertBasicHintSymbols($RegionList_ref, $Index_ref, \%Hints);
# Step2. Remove Symbols
my $SymbolIndex = $Index_ref->{Symbols};
my $AttributeIndex = $Index_ref->{Attribute};
my $NameIndex = $Index_ref->{Name};
foreach my $items (values %Hints)
{
next if(!@$items);
for(my $i=0; $i< scalar(@$items); $i++)
{
my $CurrentItem = $items->[$i]->[$SymbolIndex];
my $CurrentAttr = $items->[$i]->[$AttributeIndex];
if($i==0)
{
my $NextAttr = $items->[$i+1]->[$AttributeIndex];
delete $CurrentItem->{ZILimit} if($CurrentAttr ne "ZI");
delete $CurrentItem->{ZIBase} if($CurrentAttr ne "ZI");
delete $CurrentItem->{Limit} if($NextAttr ne "ZI");
}
elsif($i==(scalar(@$items)-1))
{
my $PrevAttr = $items->[$i-1]->[$AttributeIndex];
delete $CurrentItem->{Base};
delete $CurrentItem->{Limit} if($CurrentAttr eq "ZI");
delete $CurrentItem->{ZIBase} if($PrevAttr eq "ZI");
}
else
{
my $NextAttr = $items->[$i+1]->[$AttributeIndex];
my $PrevAttr = $items->[$i-1]->[$AttributeIndex];
delete $CurrentItem->{Base};
delete $CurrentItem->{ZILimit};
delete $CurrentItem->{Limit} if(($CurrentAttr eq "ZI" and $PrevAttr ne "ZI")
or ($CurrentAttr ne "ZI" and $NextAttr ne "ZI"));
delete $CurrentItem->{ZIBase} if(($CurrentAttr eq "ZI" and $PrevAttr eq "ZI")
or ($CurrentAttr ne "ZI"));
}
}
}
}
#****************************************************************************
sub GenSymbol_Before_InputSections # Gen_TEMPLATE_SECTION
{
my ($Info_ref, $Index_ref) = @_;
my $template;
$template = &Gen_TEMPLATE_BaseSymbol($Info_ref, $Index_ref);
if($Info_ref->[$Index_ref->{Attribute}] eq "ZI")
{
my $LimitSymbol = &Gen_TEMPLATE_LimitSymbol($Info_ref, $Index_ref);
my $ZIBaseSymbol = &Gen_TEMPLATE_ZIBaseSymbol($Info_ref, $Index_ref);
my $break = "\n" if($template ne "" and $LimitSymbol ne "");
$template .= $break . $LimitSymbol;
$break = "\n";
$break = "" if($LimitSymbol eq "" or $ZIBaseSymbol eq "");
$template .= $break . $ZIBaseSymbol;
}
return $template;
}
sub GenSymbol_After_InputSections # Gen_TEMPLATE_SECTION
{
my ($Info_ref, $Index_ref) = @_;
my $template;
my $break = "";
if($Info_ref->[$Index_ref->{Attribute}] ne "ZI")
{
$template = &Gen_TEMPLATE_LimitSymbol($Info_ref, $Index_ref);
my $ZIBaseSymbol = &Gen_TEMPLATE_ZIBaseSymbol($Info_ref, $Index_ref);
$break= "\n" if($template ne "" and $ZIBaseSymbol ne "");
$template .= $break. $ZIBaseSymbol;
$break = "";
}
my $ZILimitSymbol = &Gen_TEMPLATE_ZILimitSymbol($Info_ref, $Index_ref);
$break= "\n" if($template ne "" and $ZILimitSymbol ne "");
$template .= $break . $ZILimitSymbol;
return $template;
}
#****************************************************************************
sub GenRORWInputSections # Gen_TEMPLATE_SECTION_IN_OVERLAY
{
my ($Info_ref, $Index_ref) = @_;
return &GenInputSectionsByAttribute($Info_ref, $Index_ref, sub{ my ($file) = @_;
return $file if($file !~/ZI/);} );
}
sub GenZIInputSections # Gen_TEMPLATE_SECTION_IN_OVERLAY
{
my ($Info_ref, $Index_ref) = @_;
return &GenInputSectionsByAttribute($Info_ref, $Index_ref, sub{ my ($file) = @_;
return $file if($file =~/ZI/);} );
}
sub GenInputSectionsByAttribute # used by GenRORWInputSections and GenZIInputSections
{
my ($Info_ref, $Index_ref, $expr) = @_;
my $RegionName = $Info_ref->[$Index_ref->{Name}];
my $InputSectionFolder = &GetPath($RegionName, InputSections);
opendir( my $DIR, $InputSectionFolder) || &ldsFrame_die("Can't open $InputSectionFolder!", __FILE__, __LINE__);
my @FileList = grep { $expr->($_)=~/\.txt$|.csv$/ && -f "$InputSectionFolder$_" } readdir( $DIR );
closedir $DIR;
my $InputSections = undef;
if(scalar(@FileList)>0)
{
my ($strCommonPath, $strDefaultChipPath, $strChipDependentPath, $strHeadPath) = (undef, undef, undef, undef);
foreach my $file (@FileList)
{
my $strChip = &{$Func{GetChip}}();
my $filename = $file;
$filename =~ s/\.\S+$//;
my ($Common, $ChipDefault, $Head) = (COMMON_InputSection, ChipDependent_Default_InputSection, HEAD_InputSection);
$strChipDependentPath = $InputSectionFolder.$file if($filename =~/($strChip)$/);
$strCommonPath = $InputSectionFolder.$file if($filename =~/$Common/);
$strDefaultChipPath = $InputSectionFolder.$file if($filename =~/$ChipDefault/);
$strHeadPath = $InputSectionFolder.$file if($filename =~/$Head/);
}
if(-e $strHeadPath)
{
$InputSections = &CommonUtil::GetFileContent($strHeadPath)."\n";
}
if(-e $strChipDependentPath)
{
$InputSections .= &CommonUtil::GetFileContent($strChipDependentPath)."\n";
}
elsif(-e $strDefaultChipPath)
{
$InputSections .= &CommonUtil::GetFileContent($strDefaultChipPath)."\n";
}
$InputSections .= &CommonUtil::GetFileContent($strCommonPath);
}
return $InputSections;
}
#****************************************************************************
sub Gen_TEMPLATE_SECTION # called by GenSECTIONS() and Gen_TEMPLATE_OVERLAY()
{
my $template = <<"__TEMPLATE";
[ldsGen_RegionName] [ldsGen_VMA] [ldsGen_RegionAttr] : [ldsGen_LMA] [ldsGen_ALIGN]
{
[ldsGen_Symbol_Before_InputSections]
[ldsGen_InputSections]
. = ALIGN(4);
[ldsGen_Symbol_After_InputSections]
} [ldsGen_ExecutionRegion] [ldsGen_LoadRegion]
__TEMPLATE
}
sub Gen_TEMPLATE_SECTION_IN_OVERLAY # called by Gen_TEMPLATE_OVERLAY()
{
my $template = <<"__TEMPLATE";
[ldsGen_RegionName]
{
Image\$\$[ldsGen_RegionName]\$\$Base = ADDR([ldsGen_RegionName]);
[ldsGen_RORWInputSections]
. = ALIGN(4);
Image\$\$[ldsGen_RegionName]\$\$Limit = .;
Image\$\$[ldsGen_RegionName]\$\$ZI\$\$Base = .;
[ldsGen_ZIInputSections]
. = ALIGN(4);
Image\$\$[ldsGen_RegionName]\$\$ZI\$\$Limit = .;
}
__TEMPLATE
}
sub Gen_TEMPLATE_OVERLAY # called by FillOVERLAYSectionFrame()
{
my ($Infos_ref, $Index_ref) = @_;
my $LOADADDR_template;
map { $LOADADDR_template .= &Gen_TEMPLATE_LOADADDR($_, $Index_ref)} @$Infos_ref;
my $strOVERLAY_SECTIONS;
map {$strOVERLAY_SECTIONS .= &ProcessSection(&Gen_TEMPLATE_SECTION_IN_OVERLAY(), $_, $Index_ref)}(@$Infos_ref);
my $LengthSymbol_template;
map { $LengthSymbol_template .= &Gen_TEMPLATE_LengthSymbol($_, $Index_ref)} @$Infos_ref;
my $template = <<"__TEMPLATE";
OVERLAY [ldsGen_VMA] [ldsGen_RegionAttr] : [ldsGen_LMA] [ldsGen_ALIGN]
{
$strOVERLAY_SECTIONS
} [ldsGen_ExecutionRegion] [ldsGen_LoadRegion]
__TEMPLATE
return ($template, $LOADADDR_template, $LengthSymbol_template);
}
sub Gen_TEMPLATE_LOADADDR # Called by GenSECTIONS and Gen_TEMPLATE_OVERLAY()
{
my ($Info_ref, $Index_ref) = @_;
my $strBaseRegion = $Info_ref->[$Index_ref->{BaseRegion}];
my $strOrgRegion = $Info_ref->[$Index_ref->{Name}];
my $strType = $Info_ref->[$Index_ref->{Type}];
return "" if($strBaseRegion ne "" and $strBaseRegion ne $strOrgRegion and $strType !~ /^OVERLAY$/i);
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
my $template = <<"__TEMPLATE";
Load\$\$$strRegionName\$\$Base = LOADADDR($strRegionName);
__TEMPLATE
return $template;
}
sub Gen_TEMPLATE_LengthSymbol # Called by GenSECTIONS() and Gen_TEMPLATE_OVERLAY()
{
my ($Info_ref, $Index_ref) = @_;
my $strBaseRegion = $Info_ref->[$Index_ref->{BaseRegion}];
my $strOrgRegion = $Info_ref->[$Index_ref->{Name}];
my $strType = $Info_ref->[$Index_ref->{Type}];
return "" if($strBaseRegion ne "" and $strBaseRegion ne $strOrgRegion and $strType !~ /^OVERLAY$/i);
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
my $template = <<"__TEMPLATE";
Image\$\$$strRegionName\$\$Length = Image\$\$$strRegionName\$\$Limit - Image\$\$$strRegionName\$\$Base;
Image\$\$$strRegionName\$\$ZI\$\$Length = Image\$\$$strRegionName\$\$ZI\$\$Limit - Image\$\$$strRegionName\$\$ZI\$\$Base;
__TEMPLATE
return $template;
}
sub Gen_TEMPLATE_ASSERT
{
my ($Info_ref, $Index_ref) = @_;
my $strBaseRegion = $Info_ref->[$Index_ref->{BaseRegion}];
my $strOrgRegion = $Info_ref->[$Index_ref->{Name}];
my $strMaxSize = $Info_ref->[$Index_ref->{MaxSize}];
return "" if(($strBaseRegion ne "" and $strBaseRegion ne $strOrgRegion) or $strMaxSize eq "");
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
my $ERRTitle = genERR::SYSERR_1_2;
my $template = <<"__TEMPLATE";
ASSERT( (Image\$\$$strRegionName\$\$Length + Image\$\$$strRegionName\$\$ZI\$\$Length ) <= $strMaxSize , \"$ERRTitle\Sizes of $strRegionName exceed $strMaxSize\")
__TEMPLATE
return $template;
}
sub Gen_TEMPLATE_BaseSymbol # Called by GenSymbol_Before_InputSections()
{
my ($Info_ref, $Index_ref) = @_;
return "" if(!exists $Info_ref->[$Index_ref->{Symbols}]->{Base});
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
return ' ' x 8 . "Image\$\$$strRegionName\$\$Base = . ;";
}
sub Gen_TEMPLATE_LimitSymbol # Called by GenSymbol_(Before/After)_InputSections()
{
my ($Info_ref, $Index_ref) = @_;
return "" if(!exists $Info_ref->[$Index_ref->{Symbols}]->{Limit});
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
return ' ' x 8 . "Image\$\$$strRegionName\$\$Limit = . ;";
}
sub Gen_TEMPLATE_ZIBaseSymbol # Called by GenSymbol_(Before/After)_InputSections()
{
my ($Info_ref, $Index_ref) = @_;
return "" if(!exists $Info_ref->[$Index_ref->{Symbols}]->{ZIBase});
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
return ' ' x 8 . "Image\$\$$strRegionName\$\$ZI\$\$Base = . ;";
}
sub Gen_TEMPLATE_ZILimitSymbol # Called by GenSymbol_After_InputSections()
{
my ($Info_ref, $Index_ref) = @_;
return "" if(!exists $Info_ref->[$Index_ref->{Symbols}]->{ZILimit});
my $strRegionName = &GenBaseRegionName($Info_ref, $Index_ref);
return ' ' x 8 . "Image\$\$$strRegionName\$\$ZI\$\$Limit = . ;";
}
#****************************************************************************
# subroutine: ldsFrame_die
# sample code: (message, __FILE__, __LINE__)
# input: $error_msg, $file, $line_no
#****************************************************************************
sub ldsFrame_die
{
my ($error_msg, $file, $line_no) = (@_);
&CommonUtil::error_handler($error_msg, $file, $line_no, 'ldsFrame');
}