sector_tags.cc revision 13215
17191Sgblack@eecs.umich.edu/* 27191Sgblack@eecs.umich.edu * Copyright (c) 2018 Inria 37191Sgblack@eecs.umich.edu * All rights reserved. 47191Sgblack@eecs.umich.edu * 57191Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67191Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77191Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87191Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97191Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107191Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117191Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127191Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137191Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147191Sgblack@eecs.umich.edu * this software without specific prior written permission. 157191Sgblack@eecs.umich.edu * 167191Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177191Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187191Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197191Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207191Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217191Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227191Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237191Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247191Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257191Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267191Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277191Sgblack@eecs.umich.edu * 287191Sgblack@eecs.umich.edu * Authors: Daniel Carvalho 297191Sgblack@eecs.umich.edu */ 307191Sgblack@eecs.umich.edu 317191Sgblack@eecs.umich.edu/** 327191Sgblack@eecs.umich.edu * @file 337191Sgblack@eecs.umich.edu * Definitions of a base set associative sector tag store. 347191Sgblack@eecs.umich.edu */ 357191Sgblack@eecs.umich.edu 367191Sgblack@eecs.umich.edu#include "mem/cache/tags/sector_tags.hh" 377191Sgblack@eecs.umich.edu 387191Sgblack@eecs.umich.edu#include <cassert> 397191Sgblack@eecs.umich.edu#include <memory> 407191Sgblack@eecs.umich.edu#include <string> 417191Sgblack@eecs.umich.edu 427191Sgblack@eecs.umich.edu#include "base/intmath.hh" 437191Sgblack@eecs.umich.edu#include "base/logging.hh" 447191Sgblack@eecs.umich.edu#include "base/types.hh" 457191Sgblack@eecs.umich.edu#include "debug/CacheRepl.hh" 467191Sgblack@eecs.umich.edu#include "mem/cache/base.hh" 477308Sgblack@eecs.umich.edu#include "mem/cache/replacement_policies/base.hh" 487191Sgblack@eecs.umich.edu 497316Sgblack@eecs.umich.eduSectorTags::SectorTags(const SectorTagsParams *p) 507316Sgblack@eecs.umich.edu : BaseTags(p), assoc(p->assoc), allocAssoc(p->assoc), 517316Sgblack@eecs.umich.edu sequentialAccess(p->sequential_access), 527316Sgblack@eecs.umich.edu replacementPolicy(p->replacement_policy), 537316Sgblack@eecs.umich.edu numBlocksPerSector(p->num_blocks_per_sector), 547316Sgblack@eecs.umich.edu numSectors(numBlocks / p->num_blocks_per_sector), 557191Sgblack@eecs.umich.edu numSets(numSectors / p->assoc), 567191Sgblack@eecs.umich.edu blks(numBlocks), secBlks(numSectors), sets(numSets), 577191Sgblack@eecs.umich.edu sectorShift(floorLog2(blkSize)), 587191Sgblack@eecs.umich.edu setShift(sectorShift + floorLog2(numBlocksPerSector)), 597191Sgblack@eecs.umich.edu tagShift(setShift + floorLog2(numSets)), 607191Sgblack@eecs.umich.edu sectorMask(numBlocksPerSector - 1), setMask(numSets - 1) 617191Sgblack@eecs.umich.edu{ 627191Sgblack@eecs.umich.edu // Check parameters 637191Sgblack@eecs.umich.edu fatal_if(blkSize < 4 || !isPowerOf2(blkSize), 647191Sgblack@eecs.umich.edu "Block size must be at least 4 and a power of 2"); 657191Sgblack@eecs.umich.edu fatal_if(!isPowerOf2(numSets), 667248Sgblack@eecs.umich.edu "# of sets must be non-zero and a power of 2"); 677191Sgblack@eecs.umich.edu fatal_if(!isPowerOf2(numBlocksPerSector), 687192Sgblack@eecs.umich.edu "# of blocks per sector must be non-zero and a power of 2"); 697192Sgblack@eecs.umich.edu fatal_if(assoc <= 0, "associativity must be greater than zero"); 707192Sgblack@eecs.umich.edu 717192Sgblack@eecs.umich.edu // Initialize all sets 727192Sgblack@eecs.umich.edu unsigned sec_blk_index = 0; // index into sector blks array 737192Sgblack@eecs.umich.edu unsigned blk_index = 0; // index into blks array 747192Sgblack@eecs.umich.edu for (unsigned i = 0; i < numSets; ++i) { 757192Sgblack@eecs.umich.edu sets[i].resize(assoc); 767192Sgblack@eecs.umich.edu 777191Sgblack@eecs.umich.edu // Initialize all sectors in this set 787191Sgblack@eecs.umich.edu for (unsigned j = 0; j < assoc; ++j) { 797191Sgblack@eecs.umich.edu // Select block within the set to be linked 807192Sgblack@eecs.umich.edu SectorBlk*& sec_blk = sets[i][j]; 817192Sgblack@eecs.umich.edu 827192Sgblack@eecs.umich.edu // Locate next cache sector 837192Sgblack@eecs.umich.edu sec_blk = &secBlks[sec_blk_index]; 847192Sgblack@eecs.umich.edu 857192Sgblack@eecs.umich.edu // Associate a replacement data entry to the sector 867192Sgblack@eecs.umich.edu sec_blk->replacementData = replacementPolicy->instantiateEntry(); 877192Sgblack@eecs.umich.edu 887192Sgblack@eecs.umich.edu // Initialize all blocks in this sector 897192Sgblack@eecs.umich.edu sec_blk->blks.resize(numBlocksPerSector); 907192Sgblack@eecs.umich.edu for (unsigned k = 0; k < numBlocksPerSector; ++k){ 917192Sgblack@eecs.umich.edu // Select block within the set to be linked 927192Sgblack@eecs.umich.edu SectorSubBlk*& blk = sec_blk->blks[k]; 937192Sgblack@eecs.umich.edu 947192Sgblack@eecs.umich.edu // Locate next cache block 957192Sgblack@eecs.umich.edu blk = &blks[blk_index]; 967192Sgblack@eecs.umich.edu 977192Sgblack@eecs.umich.edu // Associate a data chunk to the block 987192Sgblack@eecs.umich.edu blk->data = &dataBlks[blkSize*blk_index]; 997192Sgblack@eecs.umich.edu 1007191Sgblack@eecs.umich.edu // Associate sector block to this block 1017191Sgblack@eecs.umich.edu blk->setSectorBlock(sec_blk); 1027191Sgblack@eecs.umich.edu 1037191Sgblack@eecs.umich.edu // Associate the sector replacement data to this block 1047191Sgblack@eecs.umich.edu blk->replacementData = sec_blk->replacementData; 1057191Sgblack@eecs.umich.edu 1067191Sgblack@eecs.umich.edu // Set its set, way and sector offset 1077191Sgblack@eecs.umich.edu blk->set = i; 1087191Sgblack@eecs.umich.edu blk->way = j; 1097191Sgblack@eecs.umich.edu blk->setSectorOffset(k); 1107191Sgblack@eecs.umich.edu 1117191Sgblack@eecs.umich.edu // Update block index 1127191Sgblack@eecs.umich.edu ++blk_index; 1137191Sgblack@eecs.umich.edu } 1147191Sgblack@eecs.umich.edu 1157191Sgblack@eecs.umich.edu // Update sector block index 1167248Sgblack@eecs.umich.edu ++sec_blk_index; 1177191Sgblack@eecs.umich.edu } 1187192Sgblack@eecs.umich.edu } 1197192Sgblack@eecs.umich.edu} 1207192Sgblack@eecs.umich.edu 1217192Sgblack@eecs.umich.eduvoid 1227192Sgblack@eecs.umich.eduSectorTags::invalidate(CacheBlk *blk) 1237192Sgblack@eecs.umich.edu{ 1247192Sgblack@eecs.umich.edu BaseTags::invalidate(blk); 1257192Sgblack@eecs.umich.edu 1267192Sgblack@eecs.umich.edu // Get block's sector 1277192Sgblack@eecs.umich.edu SectorSubBlk* sub_blk = static_cast<SectorSubBlk*>(blk); 1287192Sgblack@eecs.umich.edu const SectorBlk* sector_blk = sub_blk->getSectorBlock(); 1297192Sgblack@eecs.umich.edu 1307192Sgblack@eecs.umich.edu // When a block in a sector is invalidated, it does not make the tag 1317192Sgblack@eecs.umich.edu // invalid automatically, as there might be other blocks in the sector 1327191Sgblack@eecs.umich.edu // using it. The tag is invalidated only when there is a single block 1337192Sgblack@eecs.umich.edu // in the sector. 1347192Sgblack@eecs.umich.edu if (!sector_blk->isValid()) { 1357192Sgblack@eecs.umich.edu // Decrease the number of tags in use 1367192Sgblack@eecs.umich.edu tagsInUse--; 1377192Sgblack@eecs.umich.edu 1387192Sgblack@eecs.umich.edu // Invalidate replacement data, as we're invalidating the sector 1397192Sgblack@eecs.umich.edu replacementPolicy->invalidate(sector_blk->replacementData); 1407192Sgblack@eecs.umich.edu } 1417192Sgblack@eecs.umich.edu} 1427192Sgblack@eecs.umich.edu 1437192Sgblack@eecs.umich.eduCacheBlk* 1447192Sgblack@eecs.umich.eduSectorTags::accessBlock(Addr addr, bool is_secure, Cycles &lat) 1457192Sgblack@eecs.umich.edu{ 1467192Sgblack@eecs.umich.edu CacheBlk *blk = findBlock(addr, is_secure); 1477192Sgblack@eecs.umich.edu 1487192Sgblack@eecs.umich.edu // Access all tags in parallel, hence one in each way. The data side 1497192Sgblack@eecs.umich.edu // either accesses all blocks in parallel, or one block sequentially on 1507192Sgblack@eecs.umich.edu // a hit. Sequential access with a miss doesn't access data. 1517192Sgblack@eecs.umich.edu tagAccesses += allocAssoc; 1527192Sgblack@eecs.umich.edu if (sequentialAccess) { 1537192Sgblack@eecs.umich.edu if (blk != nullptr) { 1547192Sgblack@eecs.umich.edu dataAccesses += 1; 1557192Sgblack@eecs.umich.edu } 1567192Sgblack@eecs.umich.edu } else { 1577192Sgblack@eecs.umich.edu dataAccesses += allocAssoc*numBlocksPerSector; 1587192Sgblack@eecs.umich.edu } 1597192Sgblack@eecs.umich.edu 1607192Sgblack@eecs.umich.edu if (blk != nullptr) { 1617192Sgblack@eecs.umich.edu // If a cache hit 1627192Sgblack@eecs.umich.edu lat = accessLatency; 1637191Sgblack@eecs.umich.edu // Check if the block to be accessed is available. If not, 1647191Sgblack@eecs.umich.edu // apply the accessLatency on top of block->whenReady. 1657191Sgblack@eecs.umich.edu if (blk->whenReady > curTick() && 1667191Sgblack@eecs.umich.edu cache->ticksToCycles(blk->whenReady - curTick()) > 1677191Sgblack@eecs.umich.edu accessLatency) { 1687191Sgblack@eecs.umich.edu lat = cache->ticksToCycles(blk->whenReady - curTick()) + 1697191Sgblack@eecs.umich.edu accessLatency; 1707191Sgblack@eecs.umich.edu } 1717314Sgblack@eecs.umich.edu 1727314Sgblack@eecs.umich.edu // Update number of references to accessed block 1737314Sgblack@eecs.umich.edu blk->refCount++; 1747314Sgblack@eecs.umich.edu 1757314Sgblack@eecs.umich.edu // Get block's sector 1767314Sgblack@eecs.umich.edu SectorSubBlk* sub_blk = static_cast<SectorSubBlk*>(blk); 1777314Sgblack@eecs.umich.edu const SectorBlk* sector_blk = sub_blk->getSectorBlock(); 1787314Sgblack@eecs.umich.edu 1797314Sgblack@eecs.umich.edu // Update replacement data of accessed block, which is shared with 1807314Sgblack@eecs.umich.edu // the whole sector it belongs to 1817314Sgblack@eecs.umich.edu replacementPolicy->touch(sector_blk->replacementData); 1827314Sgblack@eecs.umich.edu } else { 1837314Sgblack@eecs.umich.edu // If a cache miss 1847314Sgblack@eecs.umich.edu lat = lookupLatency; 1857314Sgblack@eecs.umich.edu } 1867314Sgblack@eecs.umich.edu 1877314Sgblack@eecs.umich.edu return blk; 1887314Sgblack@eecs.umich.edu} 1897314Sgblack@eecs.umich.edu 1907314Sgblack@eecs.umich.educonst std::vector<SectorBlk*> 1917314Sgblack@eecs.umich.eduSectorTags::getPossibleLocations(Addr addr) const 1927314Sgblack@eecs.umich.edu{ 1937314Sgblack@eecs.umich.edu return sets[extractSet(addr)]; 1947314Sgblack@eecs.umich.edu} 1957314Sgblack@eecs.umich.edu 1967314Sgblack@eecs.umich.eduvoid 1977314Sgblack@eecs.umich.eduSectorTags::insertBlock(const Addr addr, const bool is_secure, 1987314Sgblack@eecs.umich.edu const int src_master_ID, const uint32_t task_ID, 1997191Sgblack@eecs.umich.edu CacheBlk *blk) 2007293Sgblack@eecs.umich.edu{ 2017293Sgblack@eecs.umich.edu // Do common block insertion functionality 2027293Sgblack@eecs.umich.edu BaseTags::insertBlock(addr, is_secure, src_master_ID, task_ID, blk); 2037293Sgblack@eecs.umich.edu 2047293Sgblack@eecs.umich.edu // Get block's sector 2057293Sgblack@eecs.umich.edu SectorSubBlk* sub_blk = static_cast<SectorSubBlk*>(blk); 2067293Sgblack@eecs.umich.edu const SectorBlk* sector_blk = sub_blk->getSectorBlock(); 2077293Sgblack@eecs.umich.edu 2087293Sgblack@eecs.umich.edu // When a block is inserted, the tag is only a newly used tag if the 2097293Sgblack@eecs.umich.edu // sector was not previously present in the cache. 2107293Sgblack@eecs.umich.edu // This assumes BaseTags::insertBlock does not set the valid bit. 2117293Sgblack@eecs.umich.edu if (sector_blk->isValid()) { 2127293Sgblack@eecs.umich.edu // An existing entry's replacement data is just updated 2137293Sgblack@eecs.umich.edu replacementPolicy->touch(sector_blk->replacementData); 2147293Sgblack@eecs.umich.edu } else { 2157293Sgblack@eecs.umich.edu // Increment tag counter 2167293Sgblack@eecs.umich.edu tagsInUse++; 2177293Sgblack@eecs.umich.edu 2187293Sgblack@eecs.umich.edu // A new entry resets the replacement data 2197293Sgblack@eecs.umich.edu replacementPolicy->reset(sector_blk->replacementData); 2207293Sgblack@eecs.umich.edu } 2217293Sgblack@eecs.umich.edu} 2227293Sgblack@eecs.umich.edu 2237293Sgblack@eecs.umich.eduCacheBlk* 2247293Sgblack@eecs.umich.eduSectorTags::findBlock(Addr addr, bool is_secure) const 2257293Sgblack@eecs.umich.edu{ 2267293Sgblack@eecs.umich.edu // Extract sector tag 2277191Sgblack@eecs.umich.edu const Addr tag = extractTag(addr); 2287191Sgblack@eecs.umich.edu 2297191Sgblack@eecs.umich.edu // The address can only be mapped to a specific location of a sector 2307191Sgblack@eecs.umich.edu // due to sectors being composed of contiguous-address entries 2317191Sgblack@eecs.umich.edu const Addr offset = extractSectorOffset(addr); 2327191Sgblack@eecs.umich.edu 2337191Sgblack@eecs.umich.edu // Find all possible sector locations for the given address 2347191Sgblack@eecs.umich.edu const std::vector<SectorBlk*> locations = getPossibleLocations(addr); 2357191Sgblack@eecs.umich.edu 2367191Sgblack@eecs.umich.edu // Search for block 2377191Sgblack@eecs.umich.edu for (const auto& sector : locations) { 2387191Sgblack@eecs.umich.edu auto blk = sector->blks[offset]; 2397191Sgblack@eecs.umich.edu if (blk->getTag() == tag && blk->isValid() && 2407191Sgblack@eecs.umich.edu blk->isSecure() == is_secure) { 2417191Sgblack@eecs.umich.edu return blk; 2427191Sgblack@eecs.umich.edu } 2437191Sgblack@eecs.umich.edu } 2447191Sgblack@eecs.umich.edu 2457191Sgblack@eecs.umich.edu // Did not find block 2467191Sgblack@eecs.umich.edu return nullptr; 2477191Sgblack@eecs.umich.edu} 2487191Sgblack@eecs.umich.edu 2497191Sgblack@eecs.umich.eduReplaceableEntry* 2507191Sgblack@eecs.umich.eduSectorTags::findBlockBySetAndWay(int set, int way) const 2517191Sgblack@eecs.umich.edu{ 2527191Sgblack@eecs.umich.edu return sets[set][way]; 2537191Sgblack@eecs.umich.edu} 2547191Sgblack@eecs.umich.edu 2557191Sgblack@eecs.umich.eduCacheBlk* 2567191Sgblack@eecs.umich.eduSectorTags::findVictim(Addr addr, const bool is_secure, 2577191Sgblack@eecs.umich.edu std::vector<CacheBlk*>& evict_blks) const 2587191Sgblack@eecs.umich.edu{ 2597191Sgblack@eecs.umich.edu // Get all possible locations of this sector 2607191Sgblack@eecs.umich.edu const std::vector<SectorBlk*> sector_locations = 2617191Sgblack@eecs.umich.edu getPossibleLocations(addr); 2627191Sgblack@eecs.umich.edu 2637191Sgblack@eecs.umich.edu // Check if the sector this address belongs to has been allocated 2647191Sgblack@eecs.umich.edu Addr tag = extractTag(addr); 2657191Sgblack@eecs.umich.edu SectorBlk* victim_sector = nullptr; 2667191Sgblack@eecs.umich.edu for (const auto& sector : sector_locations){ 2677191Sgblack@eecs.umich.edu if ((tag == sector->getTag()) && sector->isValid() && 2687191Sgblack@eecs.umich.edu (is_secure == sector->isSecure())){ 2697191Sgblack@eecs.umich.edu victim_sector = sector; 2707191Sgblack@eecs.umich.edu break; 2717191Sgblack@eecs.umich.edu } 2727191Sgblack@eecs.umich.edu } 2737191Sgblack@eecs.umich.edu 2747191Sgblack@eecs.umich.edu // If the sector is not present 2757191Sgblack@eecs.umich.edu if (victim_sector == nullptr){ 2767191Sgblack@eecs.umich.edu // Choose replacement victim from replacement candidates 2777191Sgblack@eecs.umich.edu victim_sector = static_cast<SectorBlk*>(replacementPolicy->getVictim( 2787191Sgblack@eecs.umich.edu std::vector<ReplaceableEntry*>( 2797191Sgblack@eecs.umich.edu sector_locations.begin(), sector_locations.end()))); 2807191Sgblack@eecs.umich.edu } 2817192Sgblack@eecs.umich.edu 2827192Sgblack@eecs.umich.edu // Get the location of the victim block within the sector 2837192Sgblack@eecs.umich.edu SectorSubBlk* victim = victim_sector->blks[extractSectorOffset(addr)]; 2847192Sgblack@eecs.umich.edu 2857192Sgblack@eecs.umich.edu // Get evicted blocks. Blocks are only evicted if the sectors mismatch and 2867192Sgblack@eecs.umich.edu // the currently existing sector is valid. 2877192Sgblack@eecs.umich.edu if ((tag == victim_sector->getTag()) && 2887192Sgblack@eecs.umich.edu (is_secure == victim_sector->isSecure())){ 2897192Sgblack@eecs.umich.edu // It would be a hit if victim was valid, and upgrades do not call 2907192Sgblack@eecs.umich.edu // findVictim, so it cannot happen 2917192Sgblack@eecs.umich.edu assert(!victim->isValid()); 2927192Sgblack@eecs.umich.edu } else { 2937293Sgblack@eecs.umich.edu // The whole sector must be evicted to make room for the new sector 2947293Sgblack@eecs.umich.edu for (const auto& blk : victim_sector->blks){ 2957293Sgblack@eecs.umich.edu evict_blks.push_back(blk); 2967293Sgblack@eecs.umich.edu } 2977293Sgblack@eecs.umich.edu } 2987293Sgblack@eecs.umich.edu 2997293Sgblack@eecs.umich.edu DPRINTF(CacheRepl, "set %x, way %x, sector offset %x: %s\n", 3007293Sgblack@eecs.umich.edu "selecting blk for replacement\n", victim->set, victim->way, 3017314Sgblack@eecs.umich.edu victim->getSectorOffset()); 3027314Sgblack@eecs.umich.edu 3037314Sgblack@eecs.umich.edu return victim; 3047314Sgblack@eecs.umich.edu} 3057314Sgblack@eecs.umich.edu 3067314Sgblack@eecs.umich.eduAddr 3077314Sgblack@eecs.umich.eduSectorTags::extractTag(Addr addr) const 3087314Sgblack@eecs.umich.edu{ 3097314Sgblack@eecs.umich.edu return addr >> tagShift; 3107192Sgblack@eecs.umich.edu} 3117191Sgblack@eecs.umich.edu 312int 313SectorTags::extractSet(Addr addr) const 314{ 315 return (addr >> setShift) & setMask; 316} 317 318int 319SectorTags::extractSectorOffset(Addr addr) const 320{ 321 return (addr >> sectorShift) & sectorMask; 322} 323 324Addr 325SectorTags::regenerateBlkAddr(const CacheBlk* blk) const 326{ 327 const SectorSubBlk* blk_cast = static_cast<const SectorSubBlk*>(blk); 328 return ((blk_cast->getTag() << tagShift) | ((Addr)blk->set << setShift) | 329 ((Addr)blk_cast->getSectorOffset() << sectorShift)); 330} 331 332void 333SectorTags::forEachBlk(std::function<void(CacheBlk &)> visitor) 334{ 335 for (SectorSubBlk& blk : blks) { 336 visitor(blk); 337 } 338} 339 340bool 341SectorTags::anyBlk(std::function<bool(CacheBlk &)> visitor) 342{ 343 for (SectorSubBlk& blk : blks) { 344 if (visitor(blk)) { 345 return true; 346 } 347 } 348 return false; 349} 350 351SectorTags * 352SectorTagsParams::create() 353{ 354 return new SectorTags(this); 355} 356