JAVASCRIPT   233

mappers.js

Guest on 22nd August 2021 06:42:32 PM

  1.  
  2. /**
  3.  * @namespace An object holding the rom memory mappers.
  4.  */
  5.  
  6. nes.mappers = {};
  7.  
  8. //
  9. //  Mapper 0
  10. //____________//
  11.  
  12. /**
  13.  * @namespace Memory Mapper 0, Direct Access
  14.  */
  15.  
  16. nes.mappers.mmc0 = {
  17.  
  18. //Properties
  19.  
  20.         /**
  21.          * The strobe index for the first controller.
  22.          * @type Number
  23.          */
  24.  
  25.         joy1Strobe:0,
  26.  
  27.         /**
  28.          * The strobe index for the second controller.
  29.          * @type Number
  30.          */
  31.  
  32.         joy2Strobe:0,
  33.  
  34.         /**
  35.          * A number used to remember the previous write to the joypad(controller) register.
  36.          * @type Number
  37.          */
  38.  
  39.         joypadLastWrite:0,
  40.  
  41. //Methods
  42.  
  43.         /**
  44.          * Resets the mapper.
  45.          */
  46.  
  47.         reset:function nes_mappers_mmc0_reset(){
  48.                 //Reset the controller read strobes.
  49.                 this.joy1Strobe = 0;
  50.                 this.joy2Strobe = 0;
  51.                 this.joypadLastWrite = 0;
  52.                 //Reset the mouse flags, used for the Nintendo Zapper implementation.
  53.                 //this.mousePressed = false;
  54.                 //this.mouseX = null;
  55.                 //this.mouseY = null;
  56.         },
  57.  
  58.         /**
  59.          * Returns the value mapped to the specified address.
  60.          * @returns {Number}
  61.          * @param {Number} address
  62.          */
  63.  
  64.         load:function nes_mappers_mmc0_load(address){
  65.                 //ROM
  66.                 if(address > 0x4017){
  67.                         return nes.cpu.mem[address];
  68.                 }
  69.                 //RAM
  70.                 if(address < 0x2000){
  71.                         return nes.cpu.mem[address&0x7FF];
  72.                 }
  73.                 //Registers
  74.                 return this.regLoad(address);
  75.         },
  76.  
  77.         /**
  78.          * Returns the combined value from the specified address and the one after it.
  79.          * @returns {Number}
  80.          * @param {Number} address
  81.          */
  82.  
  83.         load16bit:function nes_mappers_mmc0_load16Bit(address){
  84.                 //Load two addresses from memory and combine them.
  85.                 return nes.cpu.mem[address]|(nes.cpu.mem[address+1]<<8);
  86.                         //Previously used this.load(), which checked the address.
  87.         },
  88.  
  89.         /**
  90.          * Writes the specified value to the specified address.
  91.          * @param {Number} address
  92.          * @param {Number} value
  93.          */
  94.  
  95.         write:function nes_mappers_mmc0_write(address,value){
  96.                 //Check the address.
  97.                 if(address < 0x2000){
  98.                         //RAM
  99.                         nes.cpu.mem[address&0x7FF] = value;
  100.                 }
  101.                 else if(address < 0x4000){
  102.                         //PPU Registers
  103.                         nes.ppu.writeRegister(address,value);
  104.                 }
  105.                 else if(address < 0x4018){
  106.                         //IO & Sound Registers
  107.                         switch(address){
  108.  
  109.                                 //Write 0x4014, Sprite Memory DMA Access
  110.                                 case 0x4014:
  111.                                         //Cache the base address.
  112.                                         var baseAddress = value*0x100;
  113.                                         //Cache the end address.
  114.                                         var endAddress = nes.ppu.sramAddress+256;
  115.                                         //Loop 256 times, for each byte to copy.
  116.                                         for(var i=nes.ppu.sramAddress;i<endAddress;i++){
  117.                                                 //Write the byte from memory to the sprite ram.
  118.                                                 nes.ppu.writeSpriteMem(i,nes.cpu.mem[baseAddress+i]);
  119.                                         }
  120.                                         //???
  121.                                         nes.cpu.haltCycles(513);
  122.                                         break;
  123.  
  124.                                 //Write 0x4015, Sound Channel Switch, DMC Status
  125.                                 case 0x4015:
  126.                                         nes.apu.writeReg(address,value);
  127.                                         break;
  128.  
  129.                                 //Write 0x4016, Joystick Strobe Reset
  130.                                 case 0x4016:
  131.                                         if(value === 0 && this.joypadLastWrite === 1){
  132.                                                 this.joy1Strobe = 0;
  133.                                                 this.joy2Strobe = 0;
  134.                                         }
  135.                                         this.joypadLastWrite = value;
  136.                                         break;
  137.  
  138.                                 //Write 0x4000-0x4017, Sound Registers
  139.                                 default:
  140.                                         nes.apu.writeReg(address,value);
  141.  
  142.                         }
  143.                 }
  144.                 else{
  145.                         //ROM
  146.                         nes.cpu.mem[address] = value;
  147.                 }
  148.         },
  149.  
  150.         /**
  151.          * Returns the value at the specified register address.
  152.          * @type Number
  153.          * @param {Number} address
  154.          */
  155.  
  156.         regLoad:function nes_mappers_mmc0_regLoad(address){
  157.                 //The address sent should never be below 0x2000 or above 0x4017.
  158.                 //Use fourth nibble (0xF000).
  159.                 switch(address>>12){
  160.                         case 2:
  161.                                 //Fall through to PPU registers.
  162.                         case 3:
  163.                                 //PPU Registers
  164.                                 switch(address&7){
  165.  
  166.                                         //Read 0x2000, PPU Control Register
  167.                                         case 0x0:
  168.                                                 return nes.cpu.mem[0x2000];
  169.  
  170.                                         //Read 0x2001, PPU Masking Register
  171.                                         case 0x1:
  172.                                                 return nes.cpu.mem[0x2001];
  173.  
  174.                                         //Read 0x2002, PPU Status Register
  175.                                         case 0x2:
  176.                                                 //Reset the scroll and vram address toggle.
  177.                                                 nes.ppu.firstWrite = true;
  178.                                                 //Get the value from memory.
  179.                                                 var tmp = nes.cpu.mem[0x2002];
  180.                                                 //Clear the vertical blank flag, for some reason reading the status register does this.
  181.                                                 nes.cpu.mem[0x2002] &= 127;
  182.                                                 //Return the status.
  183.                                                 return tmp;
  184.  
  185.                                         //Read 0x2003, Return 0
  186.                                         case 0x3:
  187.                                                 return 0;
  188.  
  189.                                         //Read 0x2004, Sprite Memory
  190.                                         case 0x4:
  191.                                                 //Return the sprite memory at the previously set sprite ram address.
  192.                                                 return nes.ppu.spriteMem[nes.ppu.sramAddress];
  193.  
  194.                                         //Read 0x2005, Return 0
  195.                                         case 0x5:
  196.                                                 return 0;
  197.  
  198.                                         //Read 0x2006, Return 0
  199.                                         case 0x6:
  200.                                                 return 0;
  201.  
  202.                                         //Read 0x2007, VRAM
  203.                                         case 0x7:
  204.                                                 //???
  205.                                                 nes.ppu.cntsToAddress();
  206.                                                 nes.ppu.regsToAddress();
  207.                                                 //If address is in range 0x0000-0x3EFF, return buffered values.
  208.                                                 if(nes.ppu.vramAddress <= 0x3EFF){
  209.                                                         //Get the value from the previous read?
  210.                                                         var tmp = nes.ppu.vramBufferedReadValue;
  211.                                                         //Update buffered value.
  212.                                                         if(nes.ppu.vramAddress < 0x2000){
  213.                                                                 //Not mirrored, get normally.
  214.                                                                 nes.ppu.vramBufferedReadValue = nes.ppu.vramMem[nes.ppu.vramAddress];
  215.                                                                 //Mapper latch access.
  216.                                                                 nes.mmc.latchAccess(nes.ppu.vramAddress);
  217.                                                         }
  218.                                                         else{
  219.                                                                 //Mirrored, take into account the address mirroring table.
  220.                                                                 nes.ppu.vramBufferedReadValue = nes.ppu.vramMem[nes.ppu.vramMirrorTable[nes.ppu.vramAddress]];
  221.                                                         }
  222.                                                 }
  223.                                                 else{
  224.                                                         //No buffering in this mem range, read normally.
  225.                                                         var tmp = nes.ppu.vramMem[nes.ppu.vramMirrorTable[nes.ppu.vramAddress]];
  226.                                                 }
  227.                                                 //Increment the vram address by either 1 or 32, depending on bit 2 of the control register.
  228.                                                 nes.ppu.vramAddress += 1+nes.ppu.f_addrInc*31;
  229.                                                 //???
  230.                                                 nes.ppu.cntsFromAddress();
  231.                                                 nes.ppu.regsFromAddress();
  232.                                                 //Return the value.
  233.                                                 return tmp;
  234.  
  235.                                 }
  236.                                 break;
  237.                         case 4:
  238.                                 //Sound/Joypad Registers
  239.                                 switch(address){
  240.  
  241.                                         //Read 0x4015, Sound channel enable, DMC status
  242.                                         case 0x4015:
  243.                                                 return nes.apu.readReg();
  244.  
  245.                                         //Read 0x4016, Joystick 1
  246.                                         case 0x4016:
  247.                                                 //Get the button state.
  248.                                                 var tmp = nes.controllers.state1[this.joy1Strobe];
  249.                                                 //Increment the strobe.
  250.                                                 this.joy1Strobe++;
  251.                                                 //Reset it to 0 if at 24.
  252.                                                 if(this.joy1Strobe === 24){
  253.                                                         this.joy1Strobe = 0;
  254.                                                 }
  255.                                                 //Return the button state.
  256.                                                 return tmp;
  257.  
  258.                                         //Read 0x4017, Joystick 2
  259.                                         case 0x4017:
  260.                                                 //Get the button state.
  261.                                                 var tmp = nes.controllers.state2[this.joy2Strobe];
  262.                                                 //Increment the strobe.
  263.                                                 this.joy2Strobe++;
  264.                                                 //Reset it to 0 if at 24.
  265.                                                 if(this.joy2Strobe === 24){
  266.                                                         this.joy2Strobe = 0;
  267.                                                 }
  268.                                                 //Nintendo Zapper Emulation, FIXME
  269.                                                 //if(this.mousePressed){
  270.                                                 //   //Get a square around the mouse.
  271.                                                 //   var sx = Math.max(0,this.mouseX-4);
  272.                                                 //   var ex = Math.min(256,this.mouseX+4);
  273.                                                 //   var sy = Math.max(0,this.mouseY-4);
  274.                                                 //   var ey = Math.min(240,this.mouseY+4);
  275.                                                 //   var w = 0;
  276.                                                 //   //Loop through each pixel in the square.
  277.                                                 //   for(var y=sy;y<ey;y++){
  278.                                                 //         for(var x=sx;x<ex;x++){
  279.                                                 //                 //Check if a white pixel was clicked on.
  280.                                                 //                 if(nes.ppu.buffer[(y<<8)+x] === 0xFFFFFF){
  281.                                                 //                         w = 8;
  282.                                                 //                         break;
  283.                                                 //                 }
  284.                                                 //         }
  285.                                                 //   }
  286.                                                 //   //???
  287.                                                 //   w |= 16;
  288.                                                 //   return (temp|w)&0xFFFF;
  289.                                                 //}
  290.                                                 //Return the button state.
  291.                                                 return tmp;
  292.  
  293.                                 }
  294.                                 break;
  295.                 }
  296.                 return 0;
  297.         },
  298.  
  299.         /**
  300.          * Loads the data banks from the rom(nes.rom).
  301.          */
  302.  
  303.         loadROM:function nes_mappers_mmc0_loadROM(){
  304.                 //Load PRG-ROM.
  305.                 if(nes.rom.romCount > 1){
  306.                         //Load the two first banks into memory.
  307.                         this.load16kRomBank(0,0x8000);
  308.                         this.load16kRomBank(1,0xC000);
  309.                 }
  310.                 else{
  311.                         //Load the one bank into both memory locations:
  312.                         this.load16kRomBank(0,0x8000);
  313.                         this.load16kRomBank(0,0xC000);
  314.                 }
  315.                 //Load CHR-ROM.
  316.                 this.loadCHRROM();
  317.                 //Load the battery ram, if any.
  318.                 nes.loadBatteryRam();
  319.                 //Do Reset-Interrupt.
  320.                 nes.cpu.requestInterrupt(2);
  321.         },
  322.  
  323.         /**
  324.          * Loads the character rom banks from the rom(nes.rom).
  325.          */
  326.  
  327.         loadCHRROM:function nes_mappers_mmc0_loadCHRROM(){
  328.                 //Check if the rom has VROM.
  329.                 if(nes.rom.vromCount > 0){
  330.                         if(nes.rom.vromCount === 1){
  331.                                 this.load4kVromBank(0,0x0000);
  332.                                 this.load4kVromBank(0,0x1000);
  333.                         }
  334.                         else{
  335.                                 this.load4kVromBank(0,0x0000);
  336.                                 this.load4kVromBank(1,0x1000);
  337.                         }
  338.                 }
  339.         },
  340.  
  341.         /**
  342.          * Loads the specified 8 kilobyte rom bank into the specified address in memory.
  343.          * @param {Number} bank
  344.          * @param {Number} address
  345.          */
  346.  
  347.         load8kRomBank:function nes_mappers_mmc0_load8kRomBank(bank,address){
  348.                 //Load the rom bank into the specified address.
  349.                 nes.copyArrayElements(nes.rom.rom[parseInt(bank/2,10)%nes.rom.romCount],(bank%2)*8192,nes.cpu.mem,address,8192);
  350.         },
  351.  
  352.         /**
  353.          * Loads the specified 16 kilobyte rom bank into the specified address in memory.
  354.          * @param {Number} bank
  355.          * @param {Number} address
  356.          */
  357.  
  358.         load16kRomBank:function nes_mappers_mmc0_load16kRomBank(bank,address){
  359.                 //Load the rom bank into the specified address.
  360.                 nes.copyArrayElements(nes.rom.rom[bank%nes.rom.romCount],0,nes.cpu.mem,address,16384);
  361.         },
  362.  
  363.         /**
  364.          * Loads the specified 32 kilobyte rom bank into the specified address in memory.
  365.          * @param {Number} bank
  366.          * @param {Number} address
  367.          */
  368.  
  369.         load32kRomBank:function nes_mappers_mmc0_load32kRomBank(bank,address){
  370.                 //Load two 16kb banks into the specified address.
  371.                 this.load16kRomBank(bank*2,address);
  372.                 this.load16kRomBank(bank*2+1,address+16384);
  373.         },
  374.  
  375.         /**
  376.          * Loads the specified 1 kilobyte vrom bank into the specified address in memory.
  377.          * @param {Number} bank
  378.          * @param {Number} address
  379.          */
  380.  
  381.         load1kVromBank:function nes_mappers_mmc0_load8kVromBank(bank,address){
  382.                 if(nes.rom.vromCount !== 0){
  383.                         //???
  384.                         nes.ppu.triggerRendering();
  385.                         //???
  386.                         nes.copyArrayElements(nes.rom.vrom[parseInt(bank/4,10)%nes.rom.vromCount],0,nes.ppu.vramMem,(bank%4)*1024,1024);
  387.                         //Update vrom tiles.
  388.                         var vromTile = nes.rom.vromTile[bank4k];
  389.                         var baseIndex = address>>4;
  390.                         for(var i=0;i<64;i++){
  391.                                 nes.ppu.ptTile[baseIndex+i] = vromTile[((bank%4)<<6)+i];
  392.                         }
  393.                 }
  394.         },
  395.  
  396.         /**
  397.          * Loads the specified 2 kilobyte vrom bank into the specified address in memory.
  398.          * @param {Number} bank
  399.          * @param {Number} address
  400.          */
  401.  
  402.         load2kVromBank:function nes_mappers_mmc0_load2kVromBank(bank,address){
  403.                 if(nes.rom.vromCount !== 0){
  404.                         //???
  405.                         nes.ppu.triggerRendering();
  406.                         //???
  407.                         nes.copyArrayElements(nes.rom.vrom[parseInt(bank/2,10)%nes.rom.vromCount],(bank%2)*2048,nes.ppu.vramMem,address,2048);
  408.                         //Update tiles.
  409.                         var vromTile = nes.rom.vromTile[bank4k];
  410.                         var baseIndex = address>>4;
  411.                         for(var i=0;i<128;i++){
  412.                                 nes.ppu.ptTile[baseIndex+i] = vromTile[((bank%2)<<7)+i];
  413.                         }
  414.                 }
  415.         },
  416.  
  417.         /**
  418.          * Loads the specified 4 kilobyte vrom bank into the specified address in memory.
  419.          * @param {Number} bank
  420.          * @param {Number} address
  421.          */
  422.  
  423.         load4kVromBank:function nes_mappers_mmc0_load4kVromBank(bank,address){
  424.                 if(nes.rom.vromCount !== 0){
  425.                         //???
  426.                         nes.ppu.triggerRendering();
  427.                         //???
  428.                         nes.copyArrayElements(nes.rom.vrom[bank%nes.rom.vromCount],0,nes.ppu.vramMem,address,4096);
  429.                         nes.copyArrayElements(nes.rom.vromTile[bank%nes.rom.vromCount],0,nes.ppu.ptTile,address>>4,256);
  430.                 }
  431.         },
  432.  
  433.         /**
  434.          * Loads the specified 8 kilobyte vrom bank into the specified address in memory.
  435.          * @param {Number} bank
  436.          * @param {Number} address
  437.          */
  438.  
  439.         load8kVromBank:function nes_mappers_mmc0_load8kVromBank(bankStart,address){
  440.                 if(nes.rom.vromCount !== 0){
  441.                         //???
  442.                         nes.ppu.triggerRendering();
  443.                         //Load two 4kb banks into the specified address.
  444.                         this.load4kVromBank((bankStart)%nes.rom.vromCount,address);
  445.                         this.load4kVromBank((bankStart+1)%nes.rom.vromCount,address+4096);
  446.                 }
  447.         },
  448.  
  449.         /**
  450.          * @ignore
  451.          * Used by mmc2.
  452.          */
  453.          
  454.         latchAccess:function nes_mappers_mmc0_latchAccess(address){},
  455.  
  456.         /**
  457.          * @ignore
  458.          * Used by mmc3.
  459.          */
  460.  
  461.         clockIrqCounter:function nes_mappers_mmc0_clockIrqCounter(){}
  462.  
  463. };
  464.  
  465. //
  466. //  Mapper 1
  467. //____________//
  468.  
  469. /**
  470.  * @namespace Memory Mapper 1, Nintendo MMC1
  471.  * @augments nes.mappers.mmc0
  472.  */
  473.  
  474. nes.mappers.mmc1 = nes.copyObject(nes.mappers.mmc0);
  475.  
  476. nes.applyObject(nes.mappers.mmc1,{
  477.  
  478. //Properties
  479.  
  480.         /**
  481.          * Unknown
  482.          * @type Number
  483.          * @memberOf nes.mappers.mmc1
  484.          */
  485.  
  486.         regBuffer:0,
  487.  
  488.         /**
  489.          * Unknown
  490.          * @type Number
  491.          * @memberOf nes.mappers.mmc1
  492.          */
  493.  
  494.         regBufferCounter:0,
  495.  
  496.         /**
  497.          * Unknown
  498.          * @type Number
  499.          * @memberOf nes.mappers.mmc1
  500.          */
  501.  
  502.         mirroring:0,
  503.  
  504.         /**
  505.          * Unknown
  506.          * @type Number
  507.          * @memberOf nes.mappers.mmc1
  508.          */
  509.  
  510.         prgSwitchingArea:1,
  511.  
  512.         /**
  513.          * Unknown
  514.          * @type Number
  515.          * @memberOf nes.mappers.mmc1
  516.          */
  517.  
  518.         prgSwitchingSize:1,
  519.  
  520.         /**
  521.          * Unknown
  522.          * @type Number
  523.          * @memberOf nes.mappers.mmc1
  524.          */
  525.  
  526.         vromSwitchingSize:0,
  527.  
  528.         /**
  529.          * Unknown
  530.          * @type Number
  531.          * @memberOf nes.mappers.mmc1
  532.          */
  533.  
  534.         romSelectionReg0:0,
  535.  
  536.         /**
  537.          * Unknown
  538.          * @type Number
  539.          * @memberOf nes.mappers.mmc1
  540.          */
  541.  
  542.         romSelectionReg1:0,
  543.  
  544. //Methods
  545.  
  546.         /**
  547.          * Resets the mapper.
  548.          * @memberOf nes.mappers.mmc1
  549.          */
  550.  
  551.         reset:function nes_mappers_mmc1_reset(){
  552.                 //Reset most the the mapper through the mmc0 reset method.
  553.                 nes.mappers.mmc0.reset.apply(this);
  554.                 //5-bit Buffer
  555.                 this.regBuffer = 0;
  556.                 this.regBufferCounter = 0;
  557.                 //Register 0 Values
  558.                 this.mirroring = 0;
  559.                 this.oneScreenMirroring = 0;//FromBF
  560.                 this.prgSwitchingArea = 1;
  561.                 this.prgSwitchingSize = 1;
  562.                 this.vromSwitchingSize = 0;
  563.                 //Register 1 Values
  564.                 this.romSelectionReg0 = 0;
  565.                 //Register 2 Values
  566.                 this.romSelectionReg1 = 0;
  567.                 //Reguster 3
  568.                 this.romBankSelect = 0;//FromBF
  569.         },
  570.  
  571.         /**
  572.          * Similar to nes.mappers.mmc0.write(), but intercepts writes to mmc1 specific addresses.
  573.          * @param {Number} address
  574.          * @param {Number} value
  575.          * @memberOf nes.mappers.mmc1
  576.          */
  577.  
  578.         write:function nes_mappers_mmc1_write(address,value){
  579.                 //Writes below mmc1 registers are handled by mmc0.
  580.                 if(address < 0x8000){
  581.                         return nes.mappers.mmc0.write.apply(this,arguments);
  582.                 }
  583.                 //See what should be done with the written value.
  584.                 if((value&128) !== 0){
  585.                         //Reset buffering.
  586.                         this.regBufferCounter = 0;
  587.                         this.regBuffer = 0;
  588.                         //Reset register.
  589.                         if(this.getRegNumber(address) === 0){
  590.                                 this.prgSwitchingArea = 1;
  591.                                 this.prgSwitchingSize = 1;
  592.                         }
  593.                 }
  594.                 else{
  595.                         //Continue buffering.
  596.                         this.regBuffer = (this.regBuffer&(0xFF-(1<<this.regBufferCounter)))|((value&1)<<this.regBufferCounter);
  597.                         this.regBufferCounter++;
  598.                         //???
  599.                         if(this.regBufferCounter === 5){
  600.                                 //Use the buffered value.
  601.                                 this.setReg(this.getRegNumber(address),this.regBuffer);
  602.                                 //Reset buffer.
  603.                                 this.regBuffer = 0;
  604.                                 this.regBufferCounter = 0;
  605.                         }
  606.                 }
  607.         },
  608.  
  609.         /**
  610.          * Similar to nes.mappers.mmc0.setReg(), but intercepts writes to mmc1 specific registers.
  611.          * @param {Number} reg
  612.          * @param {Number} value
  613.          * @memberOf nes.mappers.mmc1
  614.          */
  615.  
  616.         setReg:function nes_mappers_mmc1_setReg(reg,value){
  617.                 switch(reg){
  618.  
  619.                         //Register 0, PPU Mirroring, ROM loading flags.
  620.                         case 0:
  621.                                 //Check if the ppu mirroring specified is different than the current.
  622.                                 if(value&3 !== this.mirroring){
  623.                                         //Set the mirroring.
  624.                                         this.mirroring = value&3;
  625.                                         //Check for singlescreen mirroring.
  626.                                         if((this.mirroring&2) === 0){
  627.                                                 nes.ppu.setMirroring(3);
  628.                                         }
  629.                                         //Else check for horizontal mirroring.
  630.                                         else if((this.mirroring&1) !== 0){
  631.                                                 nes.ppu.setMirroring(1);
  632.                                         }
  633.                                         //Else set it as vertical mirroring.
  634.                                         else{
  635.                                                 nes.ppu.setMirroring(0);
  636.                                         }
  637.                                 }
  638.                                 //Set the PRG wwitching area.
  639.                                 this.prgSwitchingArea = (value>>2)&1;
  640.                                 //Set the PRG switching size.
  641.                                 this.prgSwitchingSize = (value>>3)&1;
  642.                                 //Set the VROM switching size.
  643.                                 this.vromSwitchingSize = (value>>4)&1;
  644.                                 break;
  645.  
  646.                         //Register 1
  647.                         case 1:
  648.                                 //Set the ROM selection register 0 flag.
  649.                                 this.romSelectionReg0 = (value>>4)&1;
  650.                                 //Check whether the cart has VROM.
  651.                                 if(nes.rom.vromCount > 0){
  652.                                         //Select VROM bank at 0x0000.
  653.                                         if(this.vromSwitchingSize === 0){
  654.                                                 //Swap 8kb VROM, the location depends on the romSelectionReg0 flag.
  655.                                                 this.load8kVromBank((value&0xF)+(this.romSelectionReg0*parseInt(nes.rom.vromCount/2,10)),0x0000);
  656.                                         }
  657.                                         else{
  658.                                                 //Swap 4kb VROM, the location depends on the romSelectionReg0 flag.
  659.                                                 this.load4kVromBank((value&0xF)+(this.romSelectionReg0*parseInt(nes.rom.vromCount/2,10)),0x0000);
  660.                                         }
  661.                                 }
  662.                                 break;
  663.  
  664.                         //Register 2
  665.                         case 2:
  666.                                 //Set the ROM selection register 1 flag.
  667.                                 this.romSelectionReg1 = (value>>4)&1;
  668.                                 //Check whether the cart has VROM.
  669.                                 if(nes.rom.vromCount > 0){
  670.                                         //Select VROM bank at 0x1000.
  671.                                         if(this.vromSwitchingSize === 1){
  672.                                                 //Swap 4kB of VROM, the location depends on the romSelectionReg1 flag.
  673.                                                 this.load4kVromBank((value&0xF)+(this.romSelectionReg1*parseInt(nes.rom.vromCount/2,10)),0x1000);
  674.                                         }
  675.                                 }
  676.                                 break;
  677.  
  678.                         //Register 3, ROM bank select.
  679.                         default:
  680.                                 //Initiate the base bank as 0.
  681.                                 var baseBank = 0;
  682.                                 //Check for a size 1024 kb cart.
  683.                                 if(nes.rom.romCount >= 32){
  684.                                         if(this.vromSwitchingSize === 0 && this.romSelectionReg0 === 1){
  685.                                                 baseBank = 16;
  686.                                         }
  687.                                         else{
  688.                                                 baseBank = (this.romSelectionReg0|(this.romSelectionReg1<<1))<<3;
  689.                                         }
  690.                                 }
  691.                                 //Else check for a size 512kb cart.
  692.                                 else if(nes.rom.romCount >= 16){
  693.                                         //???
  694.                                         if(this.romSelectionReg0 === 1){
  695.                                                 baseBank = 8;
  696.                                         }
  697.                                 }
  698.                                 //Check for 32kb of rom.
  699.                                 if(this.prgSwitchingSize === 0){
  700.                                         //Load the rom bank.
  701.                                         this.load32kRomBank(baseBank+(value&0xF),0x8000);
  702.                                 }
  703.                                 //Else its 16kb or rom.
  704.                                 else{
  705.                                         //Load the rom bank.
  706.                                         this.load16kRomBank(baseBank*2+(value&0xF),0xC000-(this.prgSwitchingArea*0x4000));
  707.                                 }
  708.  
  709.                 }
  710.         },
  711.  
  712.         /**
  713.          * Returns the the register number associated with the specified address.
  714.          * @returns {Number}
  715.          * @param {Number} address
  716.          * @memberOf nes.mappers.mmc1
  717.          */
  718.  
  719.         getRegNumber:function nes_mappers_mmc1_getRegNumber(address){
  720.                 //Return the value associated with the specified address.
  721.                 if(address >= 0x8000 && address <= 0x9FFF){
  722.                         return 0;
  723.                 }
  724.                 if(address >= 0xA000 && address <= 0xBFFF){
  725.                         return 1;
  726.                 }
  727.                 if(address >= 0xC000 && address <= 0xDFFF){
  728.                         return 2;
  729.                 }
  730.                 return 3;
  731.         },
  732.  
  733.         /**
  734.          * Loads the data banks from the rom(nes.rom).
  735.          * @memberOf nes.mappers.mmc1
  736.          */
  737.  
  738.         loadROM:function nes_mappers_mmc1_loadROM(){
  739.                 //Load PRG-ROM.
  740.                 this.load16kRomBank(0,0x8000);
  741.                 this.load16kRomBank(nes.rom.romCount-1,0xC000);
  742.                 //Load CHR-ROM.
  743.                 this.loadCHRROM();
  744.                 //Load the battery ram, if any.
  745.                 nes.loadBatteryRam();
  746.                 //Do Reset-Interrupt.
  747.                 nes.cpu.requestInterrupt(2);
  748.         },
  749.  
  750.         //switchLowHighPrgRom:function nes_mappers_mmc1_switchLowHighPrgRom(oldSetting){},
  751.  
  752.         //switch16to32:function nes_mappers_mmc1_switch16to32(){},
  753.  
  754.         //switch32to16:function nes_mappers_mmc1_switch32to16(){},
  755.  
  756. });
  757.  
  758. //
  759. //  Mapper 2
  760. //____________//
  761.  
  762. /**
  763.  * @namespace Memory Mapper 2, UNROM
  764.  * @augments nes.mappers.mmc0
  765.  */
  766.  
  767. nes.mappers.mmc2 = nes.copyObject(nes.mappers.mmc0);
  768.  
  769. nes.applyObject(nes.mappers.mmc2,{
  770.  
  771.         /**
  772.          * Similar to nes.mappers.mmc0.write(), but intercepts writes to mmc2 specific addresses.
  773.          * <br>
  774.          * Member of nes.mappers.mmc2
  775.          * @param {Number} address
  776.          * @param {Number} value
  777.          */
  778.  
  779.         write:function nes_mappers_mmc2_write(address,value){
  780.                 //Writes below mmc2 registers are handled by mmc0.
  781.                 if(address < 0x8000){
  782.                         return nes.mappers.mmc0.write.apply(this,arguments);
  783.                 }
  784.                 //This is a ROM bank select command.
  785.                 //Swap in the given ROM bank at 0x8000:
  786.                 this.load16kRomBank(value,0x8000);
  787.         },
  788.  
  789.         /**
  790.          * Loads the data banks from the rom(nes.rom).
  791.          * Member of nes.mappers.mmc2
  792.          */
  793.  
  794.         loadROM:function nes_mappers_mmc2_loadROM(){
  795.                 //Load PRG-ROM.
  796.                 this.load16kRomBank(0,0x8000);
  797.                 this.load16kRomBank(nes.rom.romCount-1,0xC000);
  798.                 //Load CHR-ROM.
  799.                 this.loadCHRROM();
  800.                 //Do Reset-Interrupt.
  801.                 nes.cpu.requestInterrupt(2);
  802.         },
  803.  
  804. });
  805.  
  806. //
  807. //  Mapper 4
  808. //____________//
  809.  
  810. /**
  811.  * @namespace Memory Mapper 4, Nintendo MMC3
  812.  * @augments nes.mappers.mmc0
  813.  */
  814.  
  815. nes.mappers.mmc4 = nes.copyObject(nes.mappers.mmc0);
  816.  
  817. nes.applyObject(nes.mappers.mmc4,{
  818.  
  819.         /**
  820.          * Unknown
  821.          * @type Number
  822.          * @memberOf nes.mappers.mmc4
  823.          */
  824.  
  825.         command:null,
  826.  
  827.         /**
  828.          * Unknown
  829.          * @type Number
  830.          * @memberOf nes.mappers.mmc4
  831.          */
  832.  
  833.         prgAddressSelect:null,
  834.  
  835.         /**
  836.          * Unknown
  837.          * @type Number
  838.          * @memberOf nes.mappers.mmc4
  839.          */
  840.  
  841.         chrAddressSelect:null,
  842.  
  843.         /**
  844.          * Unknown
  845.          * @type Number
  846.          * @memberOf nes.mappers.mmc4
  847.          */
  848.  
  849.         irqCounter:null,
  850.  
  851.         /**
  852.          * Unknown
  853.          * @type Number
  854.          * @memberOf nes.mappers.mmc4
  855.          */
  856.  
  857.         irqLatchValue:null,
  858.  
  859.         /**
  860.          * Unknown
  861.          * @type Boolean
  862.          * @memberOf nes.mappers.mmc4
  863.          */
  864.  
  865.         irqEnable:false,
  866.  
  867.         /**
  868.          * Unknown
  869.          * @type Boolean
  870.          * @memberOf nes.mappers.mmc4
  871.          */
  872.  
  873.         prgAddressChanged:false,
  874.  
  875.         /**
  876.          * Similar to nes.mappers.mmc0.write(), but intercepts writes to mmc4 specific addresses.
  877.          * @param {Number} address
  878.          * @param {Number} value
  879.          * @memberOf nes.mappers.mmc4
  880.          */
  881.  
  882.         write:function nes_mappers_mmc4_write(address,value){
  883.                 //Writes below mmc4 registers are handled by mmc0.
  884.                 if(address < 0x8000){
  885.                         return nes.mappers.mmc0.write.apply(this,arguments);
  886.                 }
  887.                 //Switch through the address(registers).
  888.                 switch(address){
  889.  
  890.                         //Set Command/Address Register
  891.                         case 0x8000:
  892.                                 //Set the command from the value.
  893.                                 this.command = value&7;
  894.                                 //Check to see if the program address specified in the value is different than the current one.
  895.                                 if((value>>6)&1 !== this.prgAddressSelect){
  896.                                         //If so change it and flag it as having been changed.
  897.                                         this.prgAddressSelect = (value>>6)&1;
  898.                                         this.prgAddressChanged = true;
  899.                                 }
  900.                                 //Set the character address select flag from the value.
  901.                                 this.chrAddressSelect = (value>>7)&1;
  902.                                 break;
  903.  
  904.                         //Execute Command
  905.                         case 0x8001:
  906.                                 //Execute the command specified earlier with the specified value.
  907.                                 this.executeCommand(this.command,value);
  908.                                 break;
  909.  
  910.                         //Set PPU Mirroring
  911.                         case 0xA000:
  912.                                 //Set the ppu mirroring to vertical(0) or horizontal(1).
  913.                                 nes.ppu.setMirroring(value&1);
  914.                                 break;
  915.  
  916.                         //SaveRAM Toggle
  917.                         case 0xA001:
  918.                                 //Toggle the saveRAM, FIXME.
  919.                                 //nes.rom.setSaveState((value&1) !== 0);
  920.                                 break;
  921.  
  922.                         //Interrupt Counter Register
  923.                         case 0xC000:
  924.                                 //Set the interrupt counter to the value.
  925.                                 this.irqCounter = value;
  926.                                 //???
  927.                                 //nes.ppu.mapperIrqCounter = 0;
  928.                                 break;
  929.  
  930.                         //Latch Interrupt Register
  931.                         case 0xC001:
  932.                                 //Set the interrupt latch value.
  933.                                 this.irqLatchValue = value;
  934.                                 break;
  935.  
  936.                         //Disable the Interrupt
  937.                         case 0xE000:
  938.                                 //Set the interrupt enabled flag.
  939.                                 this.irqEnable = 0;
  940.                                 //???
  941.                                 //irqCounter = irqLatchValue;
  942.                                 break;
  943.  
  944.                         //Enable the Interrupt
  945.                         case 0xE001:
  946.                                 //Set the interrupt enabled flag.
  947.                                 this.irqEnable = 1;
  948.                                 break;
  949.  
  950.                         //Unknown Register
  951.                         default:
  952.                                 //Not a MMC4 register.
  953.                                 //The game has probably crashed, since it tries to write to rom at invalid locations.
  954.  
  955.                 }
  956.         },
  957.  
  958.         /**
  959.          * Runs the specified command with the passed argument.
  960.          * @param {Number} command
  961.          * @param {Number} argument
  962.          * @memberOf nes.mappers.mmc4
  963.          */
  964.  
  965.         executeCommand:function nes_mappers_mmc4_executeCommand(command,argument){
  966.                 switch(command){
  967.  
  968.                         //Select 2 1kb VROM pages at 0x0000.
  969.                         case 0:
  970.                                 //Load the 2 vrom banks specified by the character address flag.
  971.                                 this.load1kVromBank(argument,this.chrAddressSelect*0x1000);
  972.                                 this.load1kVromBank(argument+1,0x0400+(this.chrAddressSelect*0x1000));
  973.                                 break;
  974.  
  975.                         //Select 2 1kb VROM pages at 0x0800.
  976.                         case 1:
  977.                                 //Load the 2 vrom banks specified by the character address flag.
  978.                                 this.load1kVromBank(argument,0x0800+(this.chrAddressSelect*0x1000));
  979.                                 this.load1kVromBank(argument+1,0x0C00+(this.chrAddressSelect*0x1000));
  980.                                 break;
  981.  
  982.                         //Select 1kb VROM Page at 0x1000.
  983.                         case 2:
  984.                                 //Load the vrom bank specified by the character address select flag.
  985.                                 this.load1kVromBank(argument,this.chrAddressSelect*0x1000);
  986.                                 break;
  987.  
  988.                         //Select 1k VROM Page at 0x1400.
  989.                         case 3:
  990.                                 //Load the vrom bank specified by the character address select flag.
  991.                                 this.load1kVromBank(argument,0x1400-(this.chrAddressSelect*0x1000));
  992.                                 break;
  993.  
  994.                         //Select 1k VROM Page at 0x1800.
  995.                         case 4:
  996.                                 //Load the vrom bank specified by the character address select flag.
  997.                                 this.load1kVromBank(argument,0x1800-(this.chrAddressSelect*0x1000));
  998.                                 break;
  999.  
  1000.                         //Select 1k VROM Page at 0x1C00.
  1001.                         case 5:
  1002.                                 //Load the vrom bank specified by the character address select flag.
  1003.                                 this.load1kVromBank(argument,0x1C00-(this.chrAddressSelect*0x1000));
  1004.                                 break;
  1005.  
  1006.                         //Select ROM page 1.
  1007.                         case 6:
  1008.                                 //Check if the rom bank address changed.
  1009.                                 if(this.prgAddressChanged){
  1010.                                         //Load the hardwire bank specified by the program address select flag.
  1011.                                         this.load8kRomBank(((nes.rom.romCount-1)*2),0xC000-(this.prgAddressSelect*0x4000));
  1012.                                         //Reset the address changed flag.
  1013.                                         this.prgAddressChanged = false;
  1014.                                 }
  1015.                                 //Select first switchable ROM page.
  1016.                                 this.load8kRomBank(argument,0x8000+(this.prgAddressSelect*0x4000));
  1017.                                 break;
  1018.  
  1019.                         //Select ROM page 2.
  1020.                         case 7:
  1021.                                 //Select second switchable ROM page.
  1022.                                 this.load8kRomBank(argument,0xA000);
  1023.                                 //Check the the rom bank address changed.
  1024.                                 if(this.prgAddressChanged){
  1025.                                         //Load the hardwired bank specified by the programm address select flag.
  1026.                                         this.load8kRomBank(((nes.rom.romCount-1)*2),0xC000-(this.prgAddressSelect*0x4000));
  1027.                                         //Reset the address changed flag.
  1028.                                         this.prgAddressChanged = false;
  1029.                                 }
  1030.                                 break;
  1031.  
  1032.                 }
  1033.         },
  1034.  
  1035.         /**
  1036.          * Loads the data banks from the rom(nes.rom).
  1037.          * @memberOf nes.mappers.mmc4
  1038.          */
  1039.  
  1040.         loadROM:function nes_mappers_mmc4_loadROM(){
  1041.                 //Load hardwired PRG banks, 0xC000 and 0xE000.
  1042.                 this.load8kRomBank(((nes.rom.romCount-1)*2),0xC000);
  1043.                 this.load8kRomBank(((nes.rom.romCount-1)*2)+1,0xE000);
  1044.                 //Load swappable PRG banks, 0x8000 and 0xA000.
  1045.                 this.load8kRomBank(0,0x8000);
  1046.                 this.load8kRomBank(1,0xA000);
  1047.                 //Load CHR-ROM.
  1048.                 this.loadCHRROM();
  1049.                 //Load the battery ram, if any.
  1050.                 nes.loadBatteryRam();
  1051.                 //Do Reset-Interrupt.
  1052.                 nes.cpu.requestInterrupt(2);
  1053.         }
  1054.  
  1055. });

Raw Paste


Login or Register to edit or fork this paste. It's free.