Wikia

ROM Hack City

Comments0

Detection of SMC header in BSNES, Snes9x

Kernigh September 19, 2009 User blog:Kernigh

BSNES and Snes9x use different methods to detect if the ROM image of some SNES game has an SMC header of 512 bytes ($200 bytes in hexadecimal).

Snes9x

For Snes9x, the crucial function is CMemory::LoadROM in memmap.cpp, which calls FileLoader to read the ROM image. FileLoader reads the file and calls HeaderRemove. For each file, HeaderRemove removes the header if the file size divided by $2000 has remainder $200.

uint32 CMemory::HeaderRemove (uint32 size, int32 &headerCount, uint8 *buf)
{
        uint32  calc_size = (size / 0x2000) * 0x2000;

        if ((size - calc_size == 512 && !Settings.ForceNoHeader) || Settings.ForceHeader)
        {
                ...

                memmove(buf, buf + 512, calc_size);
                headerCount++;
                size -= 512;
        }

        return (size);
}

If HeaderRemove removed the header, then headerCount is 1, else headerCount if 0. (For a multi-file ROM image, FileLoader calls HeaderRemove for each file, so headerCount can be greater than 1.)

Then LoadROM calls ScoreLoROM and ScoreHiROM to examine the candidate SNES headers at offsets x7fc0 and xffc0. If headerCount is zero, then FileLoader again calls ScoreLoROM and ScoreHiROM to examine the candidate SNES headers at offsets x7fc0 + x200 and xffc0 + x200. If the SNES header at x7fc0 + x200 or xffc0 + x200 has the highest score, then LoadROM removes the SMC header.

int CMemory::ScoreHiROM (bool8 skip_header, int32 romoff)
{
        uint8   *buf = ROM + 0xff00 + romoff + (skip_header ? 0x200 : 0);
        ...

int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff)
{
        uint8   *buf = ROM + 0x7f00 + romoff + (skip_header ? 0x200 : 0);
        ...

bool8 CMemory::LoadROM (const char *filename)
{
        ...

        hi_score = ScoreHiROM(FALSE);
        lo_score = ScoreLoROM(FALSE);

        if (HeaderCount == 0 && !Settings.ForceNoHeader &&
                ((hi_score >  lo_score && ScoreHiROM(TRUE) > hi_score) ||
                 (hi_score <= lo_score && ScoreLoROM(TRUE) > lo_score)))
        {
                memmove(ROM, ROM + 512, totalFileSize - 512);
                totalFileSize -= 512;
                ...
                // modifying ROM, so we need to rescore
                hi_score = ScoreHiROM(FALSE);
                lo_score = ScoreLoROM(FALSE);
        }

BSNES

For BSNES, the crucial function is Utility::loadCartridge in src/ui_qt/utility/cartridge.cpp, which has exactly one line of code to check the SMC header. BSNES removes the header if the file size divided by $8000 has remainder $200.

 //remove copier header, if it exists
 if((size & 0x7fff) == 512) memmove(data, data + 512, size -= 512);

BSNES, unlike Snes9x, never uses the SNES header to decide whether to remove the SMC header. In BSNES, Cartridge::find_header in src/cartridge/header.cpp only examines the candidate SNES headers at x7fc0, xffc0 and x40ffc0.

unsigned Cartridge::find_header(const uint8_t *data, unsigned size) const {
  unsigned score_lo = score_header(data, size, 0x007fc0);
  unsigned score_hi = score_header(data, size, 0x00ffc0);
  unsigned score_ex = score_header(data, size, 0x40ffc0);
  if(score_ex) score_ex += 4;  //favor ExHiROM on images > 32mbits

  if(score_lo >= score_hi && score_lo >= score_ex) {
    return 0x007fc0;
  } else if(score_hi >= score_ex) {
    return 0x00ffc0;
  } else {
    return 0x40ffc0;
  }
}

Conclusion

Snes9x divides the ROM size by 0x2000; BSNES divides the ROM size by $8000. If the remainder equals 0x200, then these emulators remove the SMC header of $200 bytes.

Snes9x also removes the SMC header if the candidate SNES header at offset x7fc0 + x200 or xffc0 + x200 has a higher score. BSNES does not consider these candidates.

Advertisement | Your ad here

Photos

Add a Photo
10photos on this wiki
See all photos >

No recent blog posts. Write one now!


What are Wikia Blogs?

Wikia community blogs allow you to contribute a blog post to any wiki's Community Blog.

Blogs are used by wiki communities for fan fiction or original work, news and announcements, questions or recommendations to the community, or reviews or op-eds. Check out Fallout Wiki's News Blog and Lostpedia's Theories Blog to see two examples.

Around Wikia's network

Random Wiki