int romMapperPACCreate(const char* filename, UInt8* romData,
                         int size, int slot, int sslot, int startPage) 
{
    DeviceCallbacks callbacks = { destroy, NULL, saveState, loadState };
    RomMapperPAC* rm;

    rm = malloc(sizeof(RomMapperPAC));

    rm->deviceHandle = deviceManagerRegister(ROM_PAC, &callbacks, rm);
    slotRegister(slot, sslot, startPage, 2, read, read, write, destroy, rm);

    memset(rm->sram, 0xff, 0x2000);
    rm->slot  = slot;
    rm->sslot = sslot;
    rm->startPage  = startPage;
    rm->sramEnabled = 0;
    strcpy(rm->sramFilename, sramCreateFilename(filename));

    sramLoad(rm->sramFilename, rm->sram, 0x1ffe, pacHeader, strlen(pacHeader));

    slotMapPage(rm->slot, rm->sslot, rm->startPage,     NULL, 0, 0);
    slotMapPage(rm->slot, rm->sslot, rm->startPage + 1, NULL, 0, 0);

    return 1;
}
int romMapperOpcodeSaveRamCreate(int slot, int sslot, int startPage) 
{
    DeviceCallbacks callbacks = { destroy, reset, saveState, loadState };
    DebugCallbacks dbgCallbacks = { getDebugInfo, NULL, NULL, NULL };
    
    RomMapperOpcodeSaveRam* rm = malloc(sizeof(RomMapperOpcodeSaveRam));
    
    rm->slot      = slot;
    rm->sslot     = sslot;
    rm->startPage = startPage;
    
    memset(rm->saveRam, 0xff, sizeof(rm->saveRam));
    
    slotRegister(rm->slot, rm->sslot, rm->startPage, 4, NULL, NULL, write, destroy, rm);

    rm->deviceHandle = deviceManagerRegister(ROM_OPCODESAVE, &callbacks, rm);
    rm->debugHandle = debugDeviceRegister(DBGTYPE_RAM, "SAVERAM", &dbgCallbacks, rm);

    slotMapPage(rm->slot, rm->sslot, rm->startPage + 0, rm->saveRam + 0x0000, 1, 1);
    slotMapPage(rm->slot, rm->sslot, rm->startPage + 1, rm->saveRam + 0x2000, 1, 1);
    slotMapPage(rm->slot, rm->sslot, rm->startPage + 2, rm->saveRam + 0x4000, 1, 1);
    slotMapPage(rm->slot, rm->sslot, rm->startPage + 3, rm->saveRam + 0x6000, 1, 1);

    strcpy(rm->saveRamFilename, sramCreateFilename("SaveRam"));

    sramLoad(rm->saveRamFilename, rm->saveRam, sizeof(rm->saveRam), NULL, 0);

    reset(rm);

    return 1;
}
int romMapperSonyHBI55Create()
{
    DeviceCallbacks callbacks = { destroy, reset, saveState, loadState };
    DebugCallbacks dbgCallbacks = { getDebugInfo, NULL, NULL, NULL };
    SonyHBI55* rm = malloc(sizeof(SonyHBI55));

    rm->deviceHandle = deviceManagerRegister(ROM_SONYHBI55, &callbacks, rm);
    rm->debugHandle = debugDeviceRegister(DBGTYPE_CART, langDbgDevHbi55(), &dbgCallbacks, rm);

    memset(rm->sram, 0xff, sizeof(rm->sram));
    sramLoad(sramCreateFilename("HBI-55.SRAM"), rm->sram, 0x1000, NULL, 0);

    rm->sram[0] = 0x53;

    rm->i8255 = i8255Create(NULL,    NULL,    writeA,
                            NULL,    NULL,    writeB,
                            readCLo, readCLo, writeCLo,
                            readCHi, readCHi, writeCHi,
                            rm);

    ioPortRegister(0xb0, i8255Read, i8255Write, rm->i8255);
    ioPortRegister(0xb1, i8255Read, i8255Write, rm->i8255);
    ioPortRegister(0xb2, i8255Read, i8255Write, rm->i8255);
    ioPortRegister(0xb3, i8255Read, i8255Write, rm->i8255);

    reset(rm);

    return 1;
}
static void destroy(SonyHBI55* rm)
{
    ioPortUnregister(0xb0);
    ioPortUnregister(0xb1);
    ioPortUnregister(0xb2);
    ioPortUnregister(0xb3);
    
    sramSave(sramCreateFilename("HBI-55.SRAM"), rm->sram, 0x1000, NULL, 0);

    deviceManagerUnregister(rm->deviceHandle);
    debugDeviceUnregister(rm->debugHandle);

    i8255Destroy(rm->i8255);

    free(rm);
}
int romMapperSg1000CastleCreate(char* filename, UInt8* romData, 
                          int size, int slot, int sslot, int startPage) 
{
    DeviceCallbacks callbacks = { (DeviceCallback)destroy, NULL, NULL, NULL };
    RomMapperSg1000Castle* rm;
    int pages = size / 0x2000 + ((size & 0x1fff) ? 1 : 0);
    int i;

    if (size != 0x8000 || startPage != 0) {
        return 0;
    }

    rm = malloc(sizeof(RomMapperSg1000Castle));

    rm->deviceHandle = deviceManagerRegister(ROM_SG1000CASTLE, &callbacks, rm);
    slotRegister(slot, sslot, startPage, pages, NULL, NULL, NULL, (SlotEject)destroy, rm);

    rm->romData = malloc(pages * 0x2000);
    memcpy(rm->romData, romData, size);
    memset(rm->sram, 0, 0x2000);

    rm->slot  = slot;
    rm->sslot = sslot;
    rm->startPage  = startPage;
    
    strcpy(rm->sramFilename, sramCreateFilename(filename));
    sramLoad(rm->sramFilename, rm->sram, 0x2000, NULL, 0);

    for (i = 0; i < pages; i++) {
        if (i + startPage >= 2) slot = 0;
        slotMapPage(slot, sslot, i + startPage, rm->romData + 0x2000 * i, 1, 0);
    }
    // Always map SRAM in slot 0. This is an unfortunate workaround because
    // Sega roms are mapped in slot 2, but the page size is 16kB and the SRAM
    // is only 8kB which makes it impossible in current implementation to
    // map it in the same slot as the cart.
    // Note though that mapping carts to slot 2 is also sort of a workaround to
    // allow carts to be inserted/removed more easily in a running system. This
    // patch prevent removing the cart to be handled correctly though
    slotMapPage(0, 0, 4 + rm->startPage, rm->sram, 1, 1);
//    slotMapPage(rm->slot, rm->sslot, 4 + rm->startPage, rm->sram, 1, 1);

    return 1;
}