protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableRowCount = mapDescriptors.Count; var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // subi r30,r30,0x15 -> nop stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d0dc), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); // cmpwi r30,0x12 -> cmpwi r30,tableElementsCount stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d0e8), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(30, (short)(tableRowCount))); // li r0,0x15 -> nop stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d160), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); // mulli r0,r0,0x24 -> mulli r0,r0,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d16c), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 0, 0x04)); // r4 <- 804363c8 -> r4 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d170), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(4, v.upper16Bit)); stream.Write(PowerPcAsm.addi(4, 4, v.lower16Bit)); // mulli r3,r30,0x24 -> mulli r3,r30,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d178), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(3, 30, 0x04)); // subi r31,r3,0x15 -> nop stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211c04), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); // cmpwi r31,0x12 -> cmpwi r31,tableElementsCount stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211c10), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(31, (short)(tableRowCount))); // li r3,0x15 -> nop stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211c88), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); // mulli r0,r3,0x24 -> mulli r0,r3,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211c94), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 3, 0x04)); // r4 <- 804363c8 -> r4 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211c98), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(4, v.upper16Bit)); stream.Write(PowerPcAsm.addi(4, 4, v.lower16Bit)); // mulli r3,r31,0x24 -> mulli r3,r31,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211ca0), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(3, 31, 0x04)); }
private List <UInt32> writeSubroutineMakeNoneMapIconsInvisible(AddressMapper addressMapper, VAVAddr entryAddr, VAVAddr returnContinueAddr, VAVAddr returnMakeInvisibleAddr) { var Scene_Layout_Obj_SetVisible = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8006f854); // precondition: r31 MapIconButton* // r5 is unused // postcondition: r0 is map icon type // r5 is 0 var asm = new List <UInt32>(); asm.Add(PowerPcAsm.lwz(5, 0x188, 31)); // get current map id into r5 asm.Add(PowerPcAsm.cmpwi(5, -1)); // map id == -1 ? asm.Add(PowerPcAsm.bne(8)); // { asm.Add(PowerPcAsm.lwz(3, 0x28, 31)); // \ asm.Add(PowerPcAsm.li(5, 0)); // | asm.Add(PowerPcAsm.lwz(4, -0x6600, 13)); // | make "NEW" text invisible asm.Add(PowerPcAsm.bl(entryAddr, asm.Count, Scene_Layout_Obj_SetVisible)); // / asm.Add(PowerPcAsm.lwz(3, 0x28, 31)); // \ asm.Add(PowerPcAsm.li(5, 0)); // / make Locked Map Icon "(?)" invisible asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnMakeInvisibleAddr)); // returnMakeInvisibleAddr // } else { asm.Add(PowerPcAsm.lwz(0, 0x184, 3)); // get map icon type (replaced opcode) asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnContinueAddr)); // returnContinueAddr // } return(asm); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // --- Game::GetMapFrbName --- // mulli r3,r3,0x38 -> mulli r3,r3,0x10 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccab0), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(3, 3, 0x10)); // r5 <- 0x80428e50 -> r5 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccab4), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(5, v.upper16Bit)); stream.Seek(0x4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(5, 5, v.lower16Bit)); // lwz r3,0x18(r3) -> lwz r3,0x0(r3) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccac8), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(3, 0x0, 3)); // --- Game::GetMapMapNum --- // mulli r0,r3,0x38 -> mulli r0,r3,0x10 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccad0), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 3, 0x10)); // r4 <- 0x80428e50 -> r4 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccad4), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(4, v.upper16Bit)); stream.Seek(0x4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(4, 4, v.lower16Bit)); // lwz r0,0x18(r4) -> lwz r0,0x0(r4) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccae4), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(0, 0x0, 4)); // lwz r0,0x1c(r4) -> lwz r0,0x4(r4) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccaf0), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(0, 0x4, 4)); // lwz r0,0x20(r4) -> lwz r0,0x8(r4) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb00), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(0, 0x8, 4)); // lwz r0,0x24(r4) -> lwz r0,0xc(r4) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb10), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(0, 0xc, 4)); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // --- Update Table Addr --- stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801cca98), SeekOrigin.Begin); // mulli r0,r3,0x38 -> mulli r0,r3,0x04 stream.Write(PowerPcAsm.mulli(0, 3, 0x04)); // r3 <- 0x80428e50 -> r3 <- tableAddr stream.Write(PowerPcAsm.lis(3, v.upper16Bit)); stream.Write(PowerPcAsm.addi(3, 3, v.lower16Bit)); stream.Seek(0x4, SeekOrigin.Current); // lwz r3,0x10(r3) -> lwz r3,0x0(r3) stream.Write(PowerPcAsm.lwz(3, 0, 3)); // --- ASM hack: Use the rule set from map instead of from global setting --- var ruleSetFromMapRoutine = allocate(writeRuleSetFromMapRoutine(addressMapper, (VAVAddr)0), "writeRuleSetFromMapRoutine"); stream.Seek(addressMapper.toFileAddress(ruleSetFromMapRoutine), SeekOrigin.Begin); stream.Write(writeRuleSetFromMapRoutine(addressMapper, ruleSetFromMapRoutine)); // re-write the routine again since now we know where it is located in the main dol var virtualPos = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8007e13c); stream.Seek(addressMapper.toFileAddress(virtualPos), SeekOrigin.Begin); // lha r3,0x3c(r30) -> bl ruleSetFromMapRoutine stream.Write(PowerPcAsm.bl(virtualPos, ruleSetFromMapRoutine)); // cmpwi r23,0x0 -> lha r3,0x3c(r30) stream.Write(PowerPcAsm.lha(3, 0x3c, 30)); // lha r0,0x28(r30) -> cmpwi r23,0x0 stream.Write(PowerPcAsm.cmpwi(23, 0x0)); // stw r25,0x53f4(r29) -> lha r0,0x28(r30) stream.Write(PowerPcAsm.lha(0, 0x28, 30)); }
protected override Int16 readTableRowCount(EndianBinaryReader stream, AddressMapper addressMapper, bool isVanilla) { stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8007e104), SeekOrigin.Begin); var opcode = stream.ReadUInt32(); return((Int16)(PowerPcAsm.getOpcodeParameter(opcode) + 1)); }
private List <UInt32> writeSubroutineForceFetchFakeVentureCard(VAVAddr fakeVentureCard) { PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)fakeVentureCard); // precondition: r3 is ChanceCardUI * // ChanceCardUI->field_0x34 is ChanceBoard * // ChanceBoard->field_0x158 is current venture card id var asm = new List <UInt32>(); asm.Add(PowerPcAsm.lis(6, v.upper16Bit)); // \ asm.Add(PowerPcAsm.addi(6, 6, v.lower16Bit)); // / r6 <- forceVentureCardVariable asm.Add(PowerPcAsm.lwz(4, 0x0, 6)); // | r4 <- forceVentureCard asm.Add(PowerPcAsm.cmpwi(4, 0x0)); // | if(forceVentureCard != 0) asm.Add(PowerPcAsm.beq(7)); // | { asm.Add(PowerPcAsm.lwz(5, 0x34, 3)); // | r5 <- ChanceCardUI.ChanceBoard asm.Add(PowerPcAsm.stw(4, 0x158, 5)); // | ChanceBoard.currentVentureCardId <- r4 asm.Add(PowerPcAsm.li(5, 0)); // |\ forceVentureCard <- 0 asm.Add(PowerPcAsm.stw(5, 0x0, 6)); // |/ asm.Add(PowerPcAsm.li(8, 0x0)); // | r8 <- 0 (the venture card is initialized) asm.Add(PowerPcAsm.blr()); // | return r4 and r8 // | } asm.Add(PowerPcAsm.li(4, -0x1)); // | r4 <- -1 asm.Add(PowerPcAsm.li(8, 0x3)); // | r8 <- 3 (the venture card is continued to be executed) asm.Add(PowerPcAsm.blr()); // | return r4 and r8 return(asm); }
private List <UInt32> writeProcStopEventSquareRoutine(AddressMapper addressMapper, VAVAddr forceVentureCardVariable, VAVAddr routineStartAddress) { PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)forceVentureCardVariable); var gameProgressChangeModeRoutine = addressMapper.toVersionAgnosticAddress((BSVAddr)0x800c093c); var endOfSwitchCase = addressMapper.toVersionAgnosticAddress((BSVAddr)0x800fac38); var asm = new List <UInt32>(); asm.Add(PowerPcAsm.lwz(3, 0x188, 28)); // \ asm.Add(PowerPcAsm.lwz(3, 0x74, 3)); // / r3_place = gameChara.currentPlace asm.Add(PowerPcAsm.lbz(6, 0x18, 3)); // | r6_ventureCardId = r3_place.districtId asm.Add(PowerPcAsm.lis(3, v.upper16Bit)); // \ asm.Add(PowerPcAsm.addi(3, 3, v.lower16Bit)); // | forceVentureCardVariable <- r6_ventureCardId asm.Add(PowerPcAsm.stw(6, 0x0, 3)); // / asm.Add(PowerPcAsm.lwz(3, 0x18, 20)); // \ lwz r3,0x18(r20) asm.Add(PowerPcAsm.li(4, 0x1f)); // | li r4,0x1f (the GameProgress mode id 0x1f is for executing a venture card) asm.Add(PowerPcAsm.li(5, -0x1)); // | li r5,-0x1 asm.Add(PowerPcAsm.li(6, -0x1)); // | li r6,-0x1 asm.Add(PowerPcAsm.li(7, 0x0)); // | li r7,0x0 asm.Add(PowerPcAsm.bl(routineStartAddress, asm.Count, gameProgressChangeModeRoutine)); // | bl Game::GameProgress::changeMode asm.Add(PowerPcAsm.b(routineStartAddress, asm.Count, endOfSwitchCase)); // / goto end of switch case return(asm); }
protected override bool readIsVanilla(EndianBinaryReader stream, AddressMapper addressMapper) { stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8007e130), SeekOrigin.Begin); var opcode = stream.ReadUInt32(); return(opcode == PowerPcAsm.li(5, 0)); }
protected override bool readIsVanilla(EndianBinaryReader stream, AddressMapper addressMapper) { stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801cca50), SeekOrigin.Begin); var opcode = stream.ReadUInt32(); // mulli r0,r3,0x38 return(opcode == PowerPcAsm.mulli(0, 3, 0x38)); }
protected override VAVAddr readTableAddr(EndianBinaryReader stream, AddressMapper addressMapper, bool isVanilla) { stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8020d170), SeekOrigin.Begin); var lis_opcode = stream.ReadUInt32(); var addi_opcode = stream.ReadUInt32(); return((VAVAddr)PowerPcAsm.make32bitValueFromPair(lis_opcode, addi_opcode)); }
protected override bool readIsVanilla(EndianBinaryReader stream, AddressMapper addressMapper) { stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021210c), SeekOrigin.Begin); var opcode = stream.ReadUInt32(); // mulli r4,r0,0x24 return(opcode == PowerPcAsm.mulli(4, 0, 0x24)); }
protected override bool readIsVanilla(EndianBinaryReader stream, AddressMapper addressMapper) { stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021214c), SeekOrigin.Begin); var opcode = stream.ReadUInt32(); // subi r3,r3,0x15 return(opcode == PowerPcAsm.subi(3, 3, 0x15)); }
private List <UInt32> writeSubroutineGetMapsInZone(AddressMapper addressMapper, List <MapDescriptor> mapDescriptors, VAVAddr mapSetZoneOrderTable, VAVAddr entryAddr, VAVAddr returnAddr) { PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)mapSetZoneOrderTable); // precondition: r5 MapSet // r29 _ZONE_TYPE // r30 int* array containing map ids // r3,r4,r6,r7,r31 unused // postcondition: r3 num maps (must be same as in SubroutineGetNumMapsInZone) var asm = new List <UInt32>(); var asm_l2 = new List <UInt32>(); var asm_l3 = new List <UInt32>(); asm.Add(PowerPcAsm.li(3, 0)); var mapSets = (from m in mapDescriptors where m.MapSet != -1 orderby m.MapSet select m.MapSet).Distinct(); foreach (var mapSet in mapSets) { asm.Add(PowerPcAsm.cmpwi(5, mapSet)); var zones = (from m in mapDescriptors where m.MapSet == mapSet && m.Zone != -1 orderby m.Zone select m.Zone).Distinct(); asm_l2.Clear(); foreach (var zone in zones) { asm_l2.Add(PowerPcAsm.cmpwi(29, zone)); IOrderedEnumerable <MapDescriptor> maps; if (zone == 0) { maps = from m in mapDescriptors where m.MapSet == mapSet && m.Zone == 1 orderby m.Order select m; } else if (zone == 1) { maps = from m in mapDescriptors where m.MapSet == mapSet && m.Zone == 0 orderby m.Order select m; } else { maps = from m in mapDescriptors where m.MapSet == mapSet && m.Zone == zone orderby m.Order select m; } short i = 0; asm_l3.Clear(); asm_l3.Add(PowerPcAsm.li(3, (short)maps.Count())); foreach (var map in maps) { short mapId = (short)mapDescriptors.IndexOf(map); var mapDescriptor = mapDescriptors[i]; asm_l3.Add(PowerPcAsm.li(4, mapId)); asm_l3.Add(PowerPcAsm.stw(4, i, 30)); i += 4; } asm_l2.Add(PowerPcAsm.bne(asm_l3.Count + 1)); asm_l2.AddRange(asm_l3); } asm.Add(PowerPcAsm.bne(asm_l2.Count + 1)); asm.AddRange(asm_l2); } asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnAddr)); return(asm); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); stream.Seek(addressMapper.toFileAddress((BSVAddr)0x804363b8), SeekOrigin.Begin); stream.Write(Encoding.ASCII.GetBytes("NAME")); // Store the pointer to the table to some unused address. The game does not use the internal name, but CSMM uses it for the name of the map descriptor file. stream.Seek(addressMapper.toFileAddress((BSVAddr)0x804363bc), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(5, v.upper16Bit)); stream.Write(PowerPcAsm.addi(5, 5, v.lower16Bit)); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // --- Update Table Addr --- // mulli r0,r3,0x38 -> mulli r0,r3,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801cca6c), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 3, 0x04)); // r3 <- 0x80428e50 -> r3 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801cca70), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(3, v.upper16Bit)); stream.Write(PowerPcAsm.addi(3, 3, v.lower16Bit)); }
private List <UInt32> writeSubroutineSkipMapUnlockCheck(AddressMapper addressMapper, VAVAddr entryAddr, VAVAddr returnContinueAddr, VAVAddr returnSkipMapUnlockedCheck) { // precondition: r26 is mapid // r3 is unused // postcondition: r3 is mapid var asm = new List <UInt32>(); asm.Add(PowerPcAsm.or(3, 26, 26)); // r3 <- mapid asm.Add(PowerPcAsm.cmpwi(3, -1)); // mapid == -1 ? asm.Add(PowerPcAsm.beq(entryAddr, asm.Count, returnSkipMapUnlockedCheck)); // goto skipMapUnlockedCheck asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnContinueAddr)); // else goto returnContinueAddr return(asm); }
/// <summary> /// Write the subroutine which takes a compressed venture card table as input and writes it into ventureCardDecompressedTableAddr /// </summary> /// <param name="ventureCardDecompressedTableAddr">The address for the reserved memory space to store the decompressed venture card table in</param> private List <UInt32> writeSubroutine(VAVAddr ventureCardDecompressedTableAddr) { var asm = new List <UInt32>(); PowerPcAsm.Pair16Bit ventureCardTableAddrPair = PowerPcAsm.make16bitValuePair((UInt32)ventureCardDecompressedTableAddr); /// /// assume: /// r6 = ventureCardCompressedTableAddr /// /// variables: /// r4 = ventureCardId /// r5 = ventureCardCompressedTableAddr /// r6 = ventureCardDecompressedTableAddr /// r7 = ventureCardCompressedWord /// r8 = bitIndex /// r0 = tmp / currentByte /// /// return: /// r6 = ventureCardDecompressedTableAddr /// asm.Add(PowerPcAsm.li(4, 0)); // ventureCardId = 0 asm.Add(PowerPcAsm.mr(5, 6)); // r6 is ventureCardCompressedTableAddr at this point. Copy it to r5 with which we will be working asm.Add(PowerPcAsm.lis(6, ventureCardTableAddrPair.upper16Bit)); // \ load the ventureCardDecompressedTableAddr into r6. This address is asm.Add(PowerPcAsm.addi(6, 6, ventureCardTableAddrPair.lower16Bit)); // / where we will store the decompressed venture card table. int whileVentureCardIdSmaller128 = asm.Count; // do { { // asm.Add(PowerPcAsm.li(0, 0)); // \ load the next compressed word from ventureCardCompressedTableAddr asm.Add(PowerPcAsm.lwzx(7, 5, 0)); // / into r7. We will decompress the venture card table word by word. asm.Add(PowerPcAsm.li(8, 31)); // bitIndex = 31 int whileBitIndexGreaterEqual32 = asm.Count; // do { // { asm.Add(PowerPcAsm.mr(0, 7)); // get the current compressed word asm.Add(PowerPcAsm.srw(0, 0, 8)); // shift it bitIndex times to the right asm.Add(PowerPcAsm.andi(0, 0, 1)); // retrieve the lowest bit of it -> r0 contains the decompressed venture card byte now. asm.Add(PowerPcAsm.stbx(0, 4, 6)); // store it into ventureCardDecompressedTableAddr[ventureCardId] asm.Add(PowerPcAsm.subi(8, 8, 1)); // bitIndex-- asm.Add(PowerPcAsm.addi(4, 4, 1)); // ventureCardId++ asm.Add(PowerPcAsm.cmpwi(8, 0)); // asm.Add(PowerPcAsm.bge(asm.Count, whileBitIndexGreaterEqual32)); // } while(bitIndex >= 0) } // asm.Add(PowerPcAsm.addi(5, 5, 4)); // ventureCardCompressedTableAddr += 4 asm.Add(PowerPcAsm.cmpwi(4, 128)); // asm.Add(PowerPcAsm.blt(asm.Count, whileVentureCardIdSmaller128)); // } while(ventureCardId < 128) } // asm.Add(PowerPcAsm.li(4, 0)); // \ reset r4 = 0 asm.Add(PowerPcAsm.li(5, 0)); // / reset r5 = 0 asm.Add(PowerPcAsm.blr()); // return return(asm); }
private List <UInt32> writeGetTextureForCustomSquareRoutine(byte register_textureType, byte register_squareType) { var asm = new List <UInt32>(); asm.Add(PowerPcAsm.li(register_textureType, 0x1)); // textureType = 1 asm.Add(PowerPcAsm.cmpwi(register_squareType, 0x2e)); // if(squareType == 0x2e) asm.Add(PowerPcAsm.beq(2)); // { asm.Add(PowerPcAsm.blr()); // return textureType; // } else { asm.Add(PowerPcAsm.li(register_textureType, 0x5)); // textureType = 5 asm.Add(PowerPcAsm.blr()); // return textureType; // } return(asm); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // --- Game::GetMapSwitchParam --- // mulli r0,r3,0x38 -> mulli r0,r3,0x4 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb28), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 3, 0x4)); // r3 <- 0x80428e50 -> r3 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb2c), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(3, v.upper16Bit)); stream.Write(PowerPcAsm.addi(3, 3, v.lower16Bit)); // lwz r3,0x28(r3) -> lwz r3,0x0(r3) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb38), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(3, 0x0, 3)); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { short tableRowCount = (short)mapDescriptors.Count; var mapDescriptionTableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)mapDescriptionTableAddr); // HACK: Expand the description message ID table // subi r3,r3,0x15 -> nop stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021214c), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); // cmpwi r3,0x12 -> cmpwi r3,tableRowCount stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212158), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(3, tableRowCount)); // r4 <- 0x80436bc0 -> r4 <- mapDescriptionTableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212164), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(4, v.upper16Bit)); stream.Seek(4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(4, 4, v.lower16Bit)); }
public List <MapDescriptor> writeMainDol(EndianBinaryWriter stream, List <MapDescriptor> mapDescriptors, IProgress <ProgressInfo> progress) { foreach (var patch in patches) { patch.write(stream, addressMapper, mapDescriptors, freeSpaceManager, progress); } freeSpaceManager.nullTheFreeSpace(stream, addressMapper); // Write the Map Count stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801cca30), SeekOrigin.Begin); stream.Write(PowerPcAsm.li(3, (short)mapDescriptors.Count)); return(mapDescriptors); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableRowCount = mapDescriptors.Count; var tableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // --- IsMapClear(int mapId,int normalMode,UserIndex userIndex) --- /* * // subi r31,r3,0x15 -> nop * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80210434), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); * // cmpwi r31,0x12 -> cmpwi r31,tableElementsCount * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80210440), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(31, (short)(tableRowCount))); * // subi r29,r31,0x15 -> nop * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80210504), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); * // cmpwi r29,0x12 -> cmpwi r29,tableElementsCount * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80210510), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(29, (short)(tableRowCount))); * // li r0,0x15 -> nop * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80210598), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); */ // mulli r0,r0,0x24 -> mulli r0,r0,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x802105a4), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 0, 0x04)); // r3 <- 804363c8 -> r3 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x802105a8), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(3, v.upper16Bit)); stream.Seek(0x4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(3, 3, v.lower16Bit)); // mulli r0,r29,0x24 -> mulli r0,r29,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x802105c4), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 29, 0x04)); // lwz r4,0x18(r3) -> lwz r4,0x0(r3) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x802105d8), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(4, 0x0, 3)); // --- GetMapClearRank(int mapId,int normalMode) --- /* * // subi r31,r3,0x15 -> nop * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212074), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); * // cmpwi r31,0x12 -> cmpwi r31,tableElementsCount * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212080), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(31, (short)(tableRowCount))); * // li r0,0x15 -> nop * stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212100), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop()); */ // mulli r4,r0,0x24 -> mulli r4,r0,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021210c), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(4, 0, 0x04)); // r3 <- 804363c8 -> r3 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212110), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(3, v.upper16Bit)); stream.Write(PowerPcAsm.addi(3, 3, v.lower16Bit)); // mulli r0,r31,0x24 -> mulli r0,r31,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80212118), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 31, 0x04)); // lwz r3,0x18(r3) -> lwz r3,0x0(r3) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021212c), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(3, 0x0, 3)); }
private List <UInt32> writeRuleSetFromMapRoutine(AddressMapper addressMapper, VAVAddr routineStartAddress) { var Game_GetRuleFlag = addressMapper.toVersionAgnosticAddress((BSVAddr)0x801cca98); // precondition: r24 is mapId // precondition: r25 is global rule set which we are gonna use to store the linkreturn var asm = new List <UInt32>(); asm.Add(PowerPcAsm.mflr(25)); asm.Add(PowerPcAsm.mr(3, 24)); // r3 <- r24 asm.Add(PowerPcAsm.bl(routineStartAddress, asm.Count, Game_GetRuleFlag)); // r3 <- bl Game_GetRuleFlag(r3) asm.Add(PowerPcAsm.stw(3, 0x53f4, 29)); // gameRule <- r3 asm.Add(PowerPcAsm.mtlr(25)); asm.Add(PowerPcAsm.blr()); // return return(asm); }
private List <UInt32> writeSubroutineGetNumMapsInZone(List <MapDescriptor> mapDescriptors) { // precondition: r3 _ZONE_TYPE // postcondition: r3 num maps var asm = new List <UInt32>(); for (short i = 0; i < 6; i++) { asm.Add(PowerPcAsm.cmpwi(3, i)); asm.Add(PowerPcAsm.bne(3)); asm.Add(PowerPcAsm.li(3, (short)(from m in mapDescriptors where m.Zone == i && m.MapSet == 0 select m).Count())); asm.Add(PowerPcAsm.blr()); } asm.Add(PowerPcAsm.blr()); return(asm); }
protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { // hardcoded virtual address for the parameter table on how the Miis are being animated to play baseball in the background var bgSequenceMarioStadium = addressMapper.toVersionAgnosticAddress((BSVAddr)0x80428968); var tableAddr = writeTable(mapDescriptors, bgSequenceMarioStadium); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)tableAddr); // --- Update Table Addr --- // mulli r0,r3,0x38 -> mulli r0,r3,0x04 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb70), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 3, 0x04)); // r3 <- 0x80428e50 -> r3 <- tableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb74), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(3, v.upper16Bit)); stream.Write(PowerPcAsm.addi(3, 3, v.lower16Bit)); // lwz r3,0x34(r3) -> lwz r3,0x0(r3) stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801ccb80), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(3, 0x0, 3)); }
private AddressMapper setupAddressMapper(EndianBinaryReader stream, List <AddressSection> fileMappingSections, IProgress <ProgressInfo> progress) { var addressMapper = new AddressMapper(fileMappingSections); // find out the version we are dealing with // Boom Street: 8007a314: lwz r0,-0x547c(r13) stream.Seek(addressMapper.toFileAddress((VAVAddr)0x8007a314), SeekOrigin.Begin); if (stream.ReadUInt32() == PowerPcAsm.lwz(0, -0x547c, 13)) { progress?.Report("Detected game: Boom Street"); // boom street address mapper is a no-op, since the ASM hacks use the boom street virtual addresses var versionMappingSections = new List <AddressSection> { AddressSection.identity() }; addressMapper.setVersionMappingSections(versionMappingSections); } else { // Fortune Street: 8007a2c0: lwz r0,-0x547c(r13) stream.Seek(addressMapper.toFileAddress((VAVAddr)0x8007a2c0), SeekOrigin.Begin); if (stream.ReadUInt32() == PowerPcAsm.lwz(0, -0x547c, 13)) { progress?.Report("Detected game: Fortune Street"); var versionMappingSections = new List <AddressSection>(); // add mappings to translate boom street virtual addresses to fortune street virtual addresses versionMappingSections.Add(new AddressSection(0x80000100, 0x8007a283, 0x0, ".text, .data0, .data1 and beginning of .text1 until InitSoftLanguage")); versionMappingSections.Add(new AddressSection(0x8007a2f4, 0x80268717, 0x54, "continuation of .text1 until AIRegisterDMACallback")); versionMappingSections.Add(new AddressSection(0x80268720, 0x8040d97b, 0x50, "continuation of .text1")); versionMappingSections.Add(new AddressSection(0x8040d980, 0x8041027f, 0x40, ".data2, .data3 and beginning of .data4 until Boom Street / Fortune Street strings")); versionMappingSections.Add(new AddressSection(0x804105f0, 0x8044ebe7, 0x188, "continuation of .data4")); versionMappingSections.Add(new AddressSection(0x8044ec00, 0x804ac804, 0x1A0, ".data5")); versionMappingSections.Add(new AddressSection(0x804ac880, 0x8081f013, 0x200, ".uninitialized0, .data6, .uninitialized1, .data7, .uninitialized2")); addressMapper.setVersionMappingSections(versionMappingSections); } else { // unsupported version throw new ApplicationException("Only Boom Street (ST7P01) and Fortune Street (ST7E01) are supported."); } } return(addressMapper); }
private List <UInt32> writeSubroutineInitMapIdsForMapIcons(AddressMapper addressMapper, VAVAddr entryAddr) { var JUtility_memset = addressMapper.toVersionAgnosticAddress((BSVAddr)0x80004714); // precondition: r3 is newly created map icon array // r16 is the amount of map ids in the array (size / 4) // r24 is unused // postcondition: r24 is the map icon array var asm = new List <UInt32>(); asm.Add(PowerPcAsm.mflr(24)); // save the link register asm.Add(PowerPcAsm.li(4, -1)); // fill with 0xff asm.Add(PowerPcAsm.rlwinm(5, 16, 0x3, 0x0, 0x1d)); // get the size of the array asm.Add(PowerPcAsm.bl(entryAddr, asm.Count, JUtility_memset)); // call JUtility_memset(array*, 0xff, array.size) asm.Add(PowerPcAsm.mtlr(24)); // restore the link register asm.Add(PowerPcAsm.mr(24, 3)); // move array* to r24 asm.Add(PowerPcAsm.blr()); // return return(asm); }
/// <summary> /// Hijack the LoadBoard() routine. Intercept the moment when the (now compressed) ventureCardTable is passed on to the InitChanceBoard() routine. /// Call the decompressVentureCardTable routine and pass the resulting decompressed ventureCardTable (located at ventureCardDecompressedTableAddr) to the InitChanceBoard() routine instead. /// </summary> protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors) { var tableRowCount = mapDescriptors.Count; var ventureCardCompressedTableAddr = writeTable(mapDescriptors); PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)ventureCardCompressedTableAddr); // Allocate working memory space for a single uncompressed venture card table which is passed on for the game to use. We will use it to store the result of decompressing a compressed venture card table var ventureCardDecompressedTableAddr = allocate(new byte[130], "VentureCardReservedMemoryForDecompressedTable"); var ventureCardDecompressTableRoutine = allocate(writeSubroutine(ventureCardDecompressedTableAddr), "DecompressVentureCardSubroutine"); // cmplwi r24,0x29 -> cmplwi r24,ventureCardTableCount-1 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8007e104), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmplwi(24, (UInt16)(tableRowCount - 1))); // mulli r0,r24,0x82 -> mulli r0,r24,0x10 stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8007e11c), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 24, 0x10)); // r4 <- 0x80410648 -> r4 <- ventureCardCompressedTableAddr stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8007e120), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(4, v.upper16Bit)); stream.Seek(4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(4, 4, v.lower16Bit)); // li r5,0x0 -> bl ventureCardDecompressTableRoutine stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8007e130), SeekOrigin.Begin); stream.Write(PowerPcAsm.bl((UInt32)addressMapper.toVersionAgnosticAddress((BSVAddr)0x8007e130), (UInt32)ventureCardDecompressTableRoutine)); }
public List <MapDescriptor> readMainDol(EndianBinaryReader stream, IProgress <ProgressInfo> progress) { // GetMapCount stream.Seek(addressMapper.toFileAddress((BSVAddr)0x801cca30), SeekOrigin.Begin); UInt32 opcode = stream.ReadUInt32(); var count = (Int16)(PowerPcAsm.getOpcodeParameter(opcode)); List <MapDescriptor> mapDescriptors = new List <MapDescriptor>(); for (int i = 0; i < count; i++) { MapDescriptor mapDescriptor = new MapDescriptor(); mapDescriptors.Add(mapDescriptor); } foreach (var patch in patches) { patch.read(stream, addressMapper, mapDescriptors, progress); } return(mapDescriptors); }
private List <UInt32> writeUploadSimulatedButtonPress(AddressMapper addressMapper, VAVAddr routineStartAddress, VAVAddr returnAddr) { var asm = new List <UInt32>(); // 0x804363b4 (4 bytes): force simulated button press var forceSimulatedButtonPress = PowerPcAsm.make16bitValuePair((UInt32)addressMapper.toVersionAgnosticAddress((BSVAddr)0x804363b4)); var pressedButtonsBitArray = PowerPcAsm.make16bitValuePair((UInt32)addressMapper.toVersionAgnosticAddress((BSVAddr)0x8078C880)); asm.Add(PowerPcAsm.lis(6, forceSimulatedButtonPress.upper16Bit)); // \ asm.Add(PowerPcAsm.addi(6, 6, forceSimulatedButtonPress.lower16Bit)); // / r6 <- &forceSimulatedButtonPress asm.Add(PowerPcAsm.lis(7, pressedButtonsBitArray.upper16Bit)); // \ asm.Add(PowerPcAsm.addi(7, 7, pressedButtonsBitArray.lower16Bit)); // / r7 <- &pressedButtonsBitArray asm.Add(PowerPcAsm.lwz(0, 0x0, 6)); // r0 <- forceSimulatedButtonPress asm.Add(PowerPcAsm.cmpwi(0, 0x0)); // if (forceSimulatedButtonPress != 0) asm.Add(PowerPcAsm.beq(4)); // { asm.Add(PowerPcAsm.stw(0, 0x0, 7)); // pressedButtonsBitArray <- forceSimulatedButtonPress asm.Add(PowerPcAsm.li(0, 0x0)); // \ asm.Add(PowerPcAsm.stw(0, 0x0, 6)); // / forceSimulatedButtonPress <- 0 // } asm.Add(PowerPcAsm.lwz(0, 0x4, 3)); // *replaced opcode* asm.Add(PowerPcAsm.b(routineStartAddress, asm.Count, returnAddr)); // return return(asm); }