Taddress EditableLevelObjectEntryGroups::moveToNewBank(WritableROM& rom) { // std::cout << "Preparing to move to new bank" << std::endl; // More for convenience than anything else, we grab a whole bank of data // for use by this table (and a few bits of associated code). // Note that this basically requires expanding the ROM to 1 MB FreeSpaceList::iterator spaceIt = rom.freeSpace().getFreeSpace(LoadedROM::bankSize); // Throw if a full bank isn't available if (spaceIt == rom.freeSpace().freeSpaceList().end()) { throw NotEnoughSpaceException(TALES_SRCANDLINE, "EditableLevelObjectEntryGroups::" "exportToROM(WritableROM&)", LoadedROM::bankSize); } // std::cout << spaceIt->address() << " " << spaceIt->length() << std::endl; Taddress newBaseAddress = spaceIt->address(); // Claim the bank rom.freeSpace().claimSpace(spaceIt, LoadedROM::bankSize); // std::cout << "New base address: " << newBaseAddress << std::endl; // Copy code segments C1 and C3 to new bank. // C1 and C3 both contain code that references the object table, // so they must (to avoid more complicated hacking) be in the same bank. // After rearranging the code, the new bank will contain C1, C3, and // the object table, in that order, starting from the beginning of the // bank // Copy C1 to start of bank Taddress newC1Address = newBaseAddress; std::memcpy(rom.directWrite(newC1Address), codeSegmentC1, lengthOfC1Segment); // Copy C3 to directly after C1 Taddress newC3Address = newC1Address + lengthOfC1Segment; std::memcpy(rom.directWrite(newC3Address), codeSegmentC3, lengthOfC3Segment); // Set new export address for table (directly after C3) int exportAddress = newBaseAddress + lengthOfC1Segment + lengthOfC3Segment; // std::cout << "New C1 address: " << newC1Address << std::endl; // std::cout << "New C3 address: " << newC3Address << std::endl; // std::cout << "Export address: " << exportAddress << std::endl; // Update all the code that references the old locations of C1 and C3 // Get the banked address for the new direct address of C1 int newC1BankNum = LoadedROM::directToBankNum(newC1Address); int newC1BankedAddress = LoadedROM::directToBankedAddress(newC1Address); // Get the banked address for the new direct address of C3 int newC3BankNum = LoadedROM::directToBankNum(newC3Address); int newC3BankedAddress = LoadedROM::directToBankedAddress(newC3Address); // Update bank number in code that calls C1 ByteConversion::toBytes(newC1BankNum, rom.directWrite(callReferenceToC1Bank), ByteSizes::uint8Size, EndiannessTypes::little, SignednessTypes::nosign); // C1's banked address is the same (0000), so we don't need to update it // ... but do anyway for consistency ByteConversion::toBytes(newC1BankedAddress, rom.directWrite(callReferenceToC1Address), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Update banked address in code that calls C3 ByteConversion::toBytes(newC3BankNum, rom.directWrite(callReferenceToC3Bank), ByteSizes::uint8Size, EndiannessTypes::little, SignednessTypes::nosign); // Update bank number in code that calls C3. ByteConversion::toBytes(newC3BankedAddress, rom.directWrite(callReferenceToC3Address), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // C3 contains a hardcoded JP instruction into itself. Since we moved // C3, we have to update the JP to correspond to the new location. // Get new address of the JP instruction's address parameter Taddress addressOfNewJpParameter = newC3Address + offsetOfJpInC3; // Get new address of the JP instruction's jump point base Taddress addressOfNewJpBase = newC3Address + baseOffsetOfJpInC3; // Compute the new target address Taddress newJpTargetAddress = addressOfNewJpBase - absoluteLengthOfJpInC3; // std::cout << "New JP target: " << newJpTargetAddress << std::endl; // Convert to banked form Taddress newJpTargetBankedAddress = LoadedROM::directToBankedAddress(newJpTargetAddress); // Write the new target address to the JP parameter ByteConversion::toBytes(newJpTargetBankedAddress, rom.directWrite(addressOfNewJpParameter), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Get the banked address for the new direct address of the object table // int newTableBankNum // = LoadedROM::directToBankNum(exportAddress); int newTableBankedAddress = LoadedROM::directToBankedAddress(exportAddress); // Update C1 to refer to the new location of the object table ByteConversion::toBytes(newTableBankedAddress, rom.directWrite(newC1Address + offsetOfTableReferenceInC1), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Update C3 to refer to the new location of the object table ByteConversion::toBytes(newTableBankedAddress, rom.directWrite(newC3Address + offsetOfTableReferenceInC3), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Update table information // initialTableAddress_ = exportAddress; // initialTableContentSize_ = spaceIt->length() // - exportAddress // - tableHeaderSize_; // initialTableContentSize_ = exportAddress - spaceIt->address() // - tableHeaderSize_; // initialTableContentSize_ = LoadedROM::bankSize; // std::cout << initialTableContentSize_ << std::endl; // Mark that we've moved to a new bank movedToNewBank_ = true; return exportAddress; }
void MetatileStructureSet::exportToROM(WritableROM& rom) { // TODO: support for adding metatile definitions // search freespace &c FreeSpaceList::iterator spaceIt = rom.freeSpace().getFreeSpace( exportSize()); if (spaceIt == rom.freeSpace().freeSpaceList().end()) { throw NotEnoughSpaceException(TALES_SRCANDLINE, "MetatileStructureSet::exportToROM(" "WritableROM&)", exportSize()); } int writeAddress = spaceIt->address(); address_ = spaceIt->address(); rom.freeSpace().claimSpace(spaceIt, exportSize()); // std::cout << "addr: " << writeAddress << std::endl; // Starting address of structure definitions int contentStartAddress = writeAddress + (index_.size() * ByteSizes::uint16Size); // Write the index for (MetatileIndexToStructureMap::iterator it = index_.begin(); it != index_.end(); it++) { int contentIndex = it->second; // Compute the address of the content Taddress contentAddress = (contentStartAddress + (contentIndex * MetatileStructure::dataSize)); // Convert to banked address Taddress contentBankedAddress = LoadedROM ::directToBankedAddress(contentAddress); // Write to index Tbyte buffer[ByteSizes::uint16Size]; ByteConversion::toBytes(contentBankedAddress, buffer, ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); rom.directWrite(writeAddress + (it->first * ByteSizes::uint16Size), buffer, ByteSizes::uint16Size); } // Write content int metatileNum = 0; for (MetatileStructureCollection::iterator it = primaryStorage_.begin(); it != primaryStorage_.end(); it++) { // Write metatile to buffer Tbyte buffer[MetatileStructure::dataSize]; it->writeToData(buffer); // Write buffer to table rom.directWrite(contentStartAddress + (metatileNum * MetatileStructure::dataSize), buffer, MetatileStructure::dataSize); ++metatileNum; } // std::cout << "metatiles: " << metatileNum << std::endl; // std::cout << std::endl; }
void TailsAdvBank0Hacks::addUseAllInventoryHack( WritableROM& rom) { // Find free space FreeSpaceList::iterator spaceIt = rom.freeSpace().getFreeSpace(allInventoryHackCodeDataSize); // Throw if not enough space if (spaceIt == rom.freeSpace().freeSpaceList().end()) { throw NotEnoughSpaceException(TALES_SRCANDLINE, "TailsAdvBank0Hacks::addUseAllInventoryHack(" "WritableROM&)", allInventoryHackCodeDataSize); } Taddress writeAddress = spaceIt->address(); rom.freeSpace().claimSpace(spaceIt, allInventoryHackCodeDataSize); // std::cout << writeAddress << std::endl; // Write main code and data rom.directWrite(writeAddress, allInventoryHackMainData, allInventoryHackMainLength); // Fill in addresses of data tables ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress + allInventoryHackMainTable1Offset), rom.directWrite(writeAddress + allInventoryHackMainTable1ReferenceOffset), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress + allInventoryHackMainTable2Offset), rom.directWrite(writeAddress + allInventoryHackMainTable2ReferenceOffset), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Add trigger 1 rom.directWrite(allInventoryHackTrigger1Address, allInventoryHackTrigger1Data, allInventoryHackTrigger1Length); // Fill in bank ByteConversion::toBytes(LoadedROM::directToBankNum(writeAddress + allInventoryHackMainCodeStartOffset), rom.directWrite( allInventoryHackTrigger1Address + allInventoryHackTrigger1BankReferenceOffset), ByteSizes::uint8Size, EndiannessTypes::little, SignednessTypes::nosign); // Fill in address ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress + allInventoryHackMainCodeStartOffset), rom.directWrite( allInventoryHackTrigger1Address + allInventoryHackTrigger1AddressReferenceOffset), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Add trigger 2 rom.directWrite(allInventoryHackTrigger2Address, allInventoryHackTrigger2Data, allInventoryHackTrigger2Length); // Fill in bank ByteConversion::toBytes(LoadedROM::directToBankNum(writeAddress + allInventoryHackMainCodeStartOffset), rom.directWrite( allInventoryHackTrigger2Address + allInventoryHackTrigger2BankReferenceOffset), ByteSizes::uint8Size, EndiannessTypes::little, SignednessTypes::nosign); // Fill in address ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress + allInventoryHackMainCodeStartOffset), rom.directWrite( allInventoryHackTrigger2Address + allInventoryHackTrigger2AddressReferenceOffset), ByteSizes::uint16Size, EndiannessTypes::little, SignednessTypes::nosign); // Add initializer 1 rom.directWrite(allInventoryHackInitializer1Address, allInventoryHackInitializer1Data, allInventoryHackInitializer1Length); // Add initializer 2 rom.directWrite(allInventoryHackInitializer2Address, allInventoryHackInitializer2Data, allInventoryHackInitializer2Length); // Add initializer 3 rom.directWrite(allInventoryHackInitializer3Address, allInventoryHackInitializer3Data, allInventoryHackInitializer3Length); // Add initializer 4 rom.directWrite(allInventoryHackInitializer4Address, allInventoryHackInitializer4Data, allInventoryHackInitializer4Length); }