Famizork II and Nintendulator mapper DLL

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Famizork II and Nintendulator mapper DLL
by on (#142213)
Although I have made much progress it still is not completed; once it is the full source-codes will be release by public-domain. Please you can write on here whatever comment/question/answers/complaints/etc.

The mapper in use is User:Zzo38/Mapper I; an implementation for Nintendulator (in C, not C++) is listed below. This implemention tries to emulate bus conflicts too, although I do not recommend their use. It does not attempt to consider race conditions; you should still try to avoid race conditions in a program that uses it though.

I fixed interface.h to add the following codes immediately after the pragmas:
Code:
#ifndef __cplusplus
typedef struct EmulatorInterface EmulatorInterface;
typedef struct MapperInfo MapperInfo;
typedef struct ROMInfo ROMInfo;
typedef struct DLLInfo DLLInfo;
typedef enum COMPAT_TYPE COMPAT_TYPE;
typedef enum RESET_TYPE RESET_TYPE;
typedef enum STATE_TYPE STATE_TYPE;
typedef enum CFG_TYPE CFG_TYPE;
typedef enum ROM_TYPE ROM_TYPE;
#endif
Maybe you should also include it into the official file too. It can then allow mapper plugins written in C rather than only C++ mapper plugins.

Here is the implementation in Nintendulator:
Code:
/*
  Nintendulator mapper interface for Famizork II
  This program is in the public domain.
*/

#include <stdlib.h>
#include "interface.h"

HWND hWnd;
HINSTANCE hInstance;
const EmulatorInterface*EMU;
const ROMInfo*ROM;
static uint16 MapperNum=380;

static uint32 story_rom_mask;
static uint32 story_ram_mask;
static uint16 story_addr;
static uint8*story_ram[64];
static uint8*story_rom[64];
static FCPURead orig_read1;
static FCPURead orig_read3;
static FCPURead orig_read5;
static FCPUWrite orig_write1;
static FCPUWrite orig_write3;
static FCPUWrite orig_write5;

static int MAPINT Read(int Bank,int Addr) {
  int v=255;
  switch(Bank) {
    case 1: v=orig_read1(Bank,Addr); break;
    case 3: v=orig_read3(Bank,Addr); break;
  }
  if(Addr&2048) {
    if(Addr&4) {
      v&=story_rom[((story_addr|(Addr<<16))&story_rom_mask)>>12][story_addr&story_rom_mask&0xFFF];
    } else {
      v&=story_ram[((story_addr|(Addr<<16))&story_ram_mask)>>12][story_addr&story_ram_mask&0xFFF];
    }
  }
  if(Addr&16) story_addr=(story_addr&0xFF00)|(v&255);
  if(Addr&32) story_addr=(story_addr&0x00FF)|((v&255)<<8);
  return v;
}

static void MAPINT Write(int Bank,int Addr,int Val) {
  int v=Val&255;
  if(Addr&2048) {
    if(Addr&4) {
      v&=story_rom[((story_addr|(Addr<<16))&story_rom_mask)>>12][story_addr&story_rom_mask&0xFFF];
    } else {
      story_ram[((story_addr|(Addr<<16))&story_ram_mask)>>12][story_addr&story_ram_mask&0xFFF]=v;
    }
  }
  if(Addr&16) story_addr=(story_addr&0xFF00)|(v&255);
  if(Addr&32) story_addr=(story_addr&0x00FF)|((v&255)<<8);
  switch(Bank) {
    case 1: orig_write1(Bank,Addr,v); break;
    case 3: orig_write3(Bank,Addr,v); break;
  }
}

static int MAPINT SaveLoad(STATE_TYPE mode,int offset,unsigned char*data) {
  SAVELOAD_WORD(mode,offset,data,story_addr);
  return offset;
}

static BOOL MAPINT Load(void) {
  return TRUE;
}

static void MAPINT Reset(RESET_TYPE typ) {
  int i;
  if(ROM->INES_Flags&1) EMU->Mirror_V(); else EMU->Mirror_H();
  switch(ROM->INES_PRGSize) {
    case 1: // 8K story + 8K interpreter
      story_rom_mask=0x1FFF;
      EMU->SetPRG_ROM8(0x8,1);
      EMU->SetPRG_ROM8(0xA,1);
      EMU->SetPRG_ROM8(0xC,1);
      EMU->SetPRG_ROM8(0xE,1);
      break;
    case 2: // 16K story + 16K interpreter
      story_rom_mask=0x3FFF;
      EMU->SetPRG_ROM8(0x8,2);
      EMU->SetPRG_ROM8(0xA,3);
      EMU->SetPRG_ROM8(0xC,2);
      EMU->SetPRG_ROM8(0xE,3);
      break;
    case 3: // 16K story + 32K interpreter
      story_rom_mask=0x3FFF;
      EMU->SetPRG_ROM8(0x8,2);
      EMU->SetPRG_ROM8(0xA,3);
      EMU->SetPRG_ROM8(0xC,4);
      EMU->SetPRG_ROM8(0xE,5);
      break;
    case 4: // 32K story + 32K interpreter
      story_rom_mask=0x7FFF;
      EMU->SetPRG_ROM8(0x8,4);
      EMU->SetPRG_ROM8(0xA,5);
      EMU->SetPRG_ROM8(0xC,6);
      EMU->SetPRG_ROM8(0xE,7);
      break;
    case 5: // 64K story + 16K interpreter
      story_rom_mask=0xFFFF;
      EMU->SetPRG_ROM8(0x8,8);
      EMU->SetPRG_ROM8(0xA,9);
      EMU->SetPRG_ROM8(0xC,8);
      EMU->SetPRG_ROM8(0xE,9);
      break;
    case 6: // 64K story + 32K interpreter
      story_rom_mask=0xFFFF;
      EMU->SetPRG_ROM8(0x8,8);
      EMU->SetPRG_ROM8(0xA,9);
      EMU->SetPRG_ROM8(0xC,10);
      EMU->SetPRG_ROM8(0xE,11);
      break;
    case 9: // 128K story + 16K interpreter
      story_rom_mask=0x1FFFF;
      EMU->SetPRG_ROM8(0x8,16);
      EMU->SetPRG_ROM8(0xA,17);
      EMU->SetPRG_ROM8(0xC,16);
      EMU->SetPRG_ROM8(0xE,17);
      break;
    case 10: // 128K story + 32K interpreter
      story_rom_mask=0x1FFFF;
      EMU->SetPRG_ROM8(0x8,16);
      EMU->SetPRG_ROM8(0xA,17);
      EMU->SetPRG_ROM8(0xC,18);
      EMU->SetPRG_ROM8(0xE,19);
      break;
    case 17: // 256K story + 16K interpreter
      story_rom_mask=0x3FFFF;
      EMU->SetPRG_ROM8(0x8,32);
      EMU->SetPRG_ROM8(0xA,33);
      EMU->SetPRG_ROM8(0xC,32);
      EMU->SetPRG_ROM8(0xE,33);
      break;
    case 18: // 256K story + 32K interpreter
      story_rom_mask=0x3FFFF;
      EMU->SetPRG_ROM8(0x8,32);
      EMU->SetPRG_ROM8(0xA,33);
      EMU->SetPRG_ROM8(0xC,34);
      EMU->SetPRG_ROM8(0xE,35);
      break;
  }
  if(ROM->INES_CHRSize) EMU->SetCHR_ROM8(0,0);
  story_ram_mask=(64<<((ROM->INES2_PRGRAM|(ROM->INES2_PRGRAM>>4))&15))-1;
  if(ROM->INES_Flags&2) EMU->Set_SRAMSize(64<<(ROM->INES2_PRGRAM>>4));
  EMU->SetPRG_ROM4(6,story_rom_mask>>12);
  for(i=0;i<64;i++) {
    EMU->SetPRG_ROM4(6,i&(story_rom_mask>>12));
    story_rom[i]=EMU->GetPRG_Ptr4(6);
  }
  EMU->SetPRG_RAM4(6,story_ram_mask>>12);
  for(i=0;i<64;i++) {
    EMU->SetPRG_RAM4(6,i&(story_ram_mask>>12));
    story_ram[i]=EMU->GetPRG_Ptr4(6);
  }
  EMU->SetPRG_OB4(6);
  orig_read1=EMU->GetCPUReadHandler(1);
  orig_read3=EMU->GetCPUReadHandler(3);
  orig_read5=EMU->GetCPUReadHandler(5);
  orig_write1=EMU->GetCPUWriteHandler(1);
  orig_write3=EMU->GetCPUWriteHandler(3);
  orig_write5=EMU->GetCPUWriteHandler(5);
  EMU->SetCPUReadHandler(1,Read);
  EMU->SetCPUReadHandler(3,Read);
  EMU->SetCPUReadHandler(5,Read);
  EMU->SetCPUReadHandler(7,Read);
  EMU->SetCPUWriteHandler(1,Write);
  EMU->SetCPUWriteHandler(3,Write);
  EMU->SetCPUWriteHandler(5,Write);
  EMU->SetCPUWriteHandler(7,Write);
}

static const MapperInfo the_mapper={
  .MapperId=&MapperNum,
  .Description=_T("Famizork II"),
  .Compatibility=COMPAT_FULL,
  .Load=Load,
  .Reset=Reset,
  .SaveLoad=SaveLoad,
};

static void MAPINT UnloadMapper(void) {
  ROM=0;
}

static const MapperInfo*MAPINT LoadMapper (const ROMInfo*_ROM) {
  ROM=_ROM;
  if(ROM->ROMType!=ROM_INES || ROM->INES_MapperNum!=MapperNum) {
    UnloadMapper();
    return 0;
  }
  return &the_mapper;
}

DLLInfo   DLL_Info={
  _T("famizorkii_mapper.dll by zzo38"),
  0x20150303,
  0x00010000,
  LoadMapper,
  UnloadMapper
};

__declspec(dllexport) void MAPINT UnloadMapperDLL (void) {
  EMU = NULL;
  hWnd = NULL;
}

__declspec(dllexport) DLLInfo*MAPINT LoadMapperDLL (HWND hWndEmu, const EmulatorInterface *_EMU, int VersionRequired) {
  hWnd = hWndEmu;
  EMU = _EMU;
  if(VersionRequired != CurrentMapperInterface) {
    UnloadMapperDLL();
    return NULL;
  }
  return &DLL_Info;
}

BOOL   WINAPI   DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
   hInstance = hinstDLL;
   return TRUE;
}
Note: I compile using GNU C on MinGW, not using Microsoft. (I didn't get any compiler errors/warnings.)

I will also show you a few of the macros right now (maybe you can learn the working of macros in Unofficial-MagicKit then):
Code:
   ; Z-character-decoding assigning macro
   macro def_zchars
   if \#=1
   macset 2,4,\1
   else
   macset 2,4,\2
   endif
   macset 1,4,\1
   macset 3,4,*
   macset 4,4,?B
   bank bank(zchad)
   macgoto def_zchars_0
   endm

   macro def_zchars_0
   macset 5,4,\1=\2
   org zchad+\1
   db low(\3-1)
   if \3<$FE01
   fail "Z-character routine out of range"
   endif
   if \3>$FF00
   fail "Z-character routine out of range"
   endif
   macset 1,4,\1+1
   macgoto def_zchars_\5
   endm

   macro def_zchars_1
   bank \4
   org \3
   endm

   ; Instruction assigning macro
   macro def_inst
   macset 2,4,*
   macset 3,4,?B
   bank bank(instadl)
   org instadl+(\1)
   db low(\2-1)
   org instadh+(\1)
   db high(\2-1)
   bank \3
   org \2
   endm

   macro def_inst_2op
   def_inst (\1)+$00
   def_inst (\1)+$20
   def_inst (\1)+$40
   def_inst (\1)+$60
   def_inst (\1)+$C0
   endm

   macro def_inst_2op_eq
   def_inst (\1)+$00
   def_inst (\1)+$20
   def_inst (\1)+$40
   def_inst (\1)+$60
   endm

   macro def_inst_1op
   def_inst (\1)+$00
   def_inst (\1)+$10
   def_inst (\1)+$20
   endm

   macro def_inst_0op
   def_inst (\1)+$00
   endm

   macro def_inst_ext
   def_inst (\1)+$00
   endm


If you have other questions about Famizork II, please write it on here
Re: Famizork II and Nintendulator mapper DLL
by on (#142389)
The NES 2.0 supporting in Unofficial-MagicKit was defective, but I have fixed it now: http://zzo38computer.org/nes_program/ppmck.zip