1 // Portions copyright 2013 Google, Inc
3 // Copyright (C) 2010 - 2012 Grant Galitz
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License version 2 as
6 // published by the Free Software Foundation.
7 // The full license is available at http://www.gnu.org/licenses/gpl.html
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 // See the GNU General Public License for more details.
13 // The code has been adapted for use as a benchmark by Google.
15 // Previous files are in gbemu-part1.js, since they need to run in sloppy mode.
17 // Start of js/GameBoyCore.js file.
21 * JavaScript GameBoy Color Emulator
22 * Copyright (C) 2010 - 2012 Grant Galitz
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * version 2 as published by the Free Software Foundation.
27 * The full license is available at http://www.gnu.org/licenses/gpl.html
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
35 function GameBoyCore(canvas, ROMImage) {
37 this.canvas = canvas; //Canvas DOM object for drawing out the graphics to.
38 this.drawContext = null; // LCD Context
39 this.ROMImage = ROMImage; //The game's ROM.
40 //CPU Registers and Flags:
41 this.registerA = 0x01; //Register A (Accumulator)
42 this.FZero = true; //Register F - Result was zero
43 this.FSubtract = false; //Register F - Subtraction was executed
44 this.FHalfCarry = true; //Register F - Half carry or half borrow
45 this.FCarry = true; //Register F - Carry or borrow
46 this.registerB = 0x00; //Register B
47 this.registerC = 0x13; //Register C
48 this.registerD = 0x00; //Register D
49 this.registerE = 0xD8; //Register E
50 this.registersHL = 0x014D; //Registers H and L combined
51 this.stackPointer = 0xFFFE; //Stack Pointer
52 this.programCounter = 0x0100; //Program Counter
53 //Some CPU Emulation State Variables:
54 this.CPUCyclesTotal = 0; //Relative CPU clocking to speed set, rounded appropriately.
55 this.CPUCyclesTotalBase = 0; //Relative CPU clocking to speed set base.
56 this.CPUCyclesTotalCurrent = 0; //Relative CPU clocking to speed set, the directly used value.
57 this.CPUCyclesTotalRoundoff = 0; //Clocking per iteration rounding catch.
58 this.baseCPUCyclesPerIteration = 0; //CPU clocks per iteration at 1x speed.
59 this.remainingClocks = 0; //HALT clocking overrun carry over.
60 this.inBootstrap = true; //Whether we're in the GBC boot ROM.
61 this.usedBootROM = false; //Updated upon ROM loading...
62 this.usedGBCBootROM = false; //Did we boot to the GBC boot ROM?
63 this.halt = false; //Has the CPU been suspended until the next interrupt?
64 this.skipPCIncrement = false; //Did we trip the DMG Halt bug?
65 this.stopEmulator = 3; //Has the emulation been paused or a frame has ended?
66 this.IME = true; //Are interrupts enabled?
67 this.IRQLineMatched = 0; //CPU IRQ assertion.
68 this.interruptsRequested = 0; //IF Register
69 this.interruptsEnabled = 0; //IE Register
70 this.hdmaRunning = false; //HDMA Transfer Flag - GBC only
71 this.CPUTicks = 0; //The number of clock cycles emulated.
72 this.doubleSpeedShifter = 0; //GBC double speed clocking shifter.
73 this.JoyPad = 0xFF; //Joypad State (two four-bit states actually)
74 this.CPUStopped = false; //CPU STOP status.
75 //Main RAM, MBC RAM, GBC Main RAM, VRAM, etc.
76 this.memoryReader = []; //Array of functions mapped to read back memory
77 this.memoryWriter = []; //Array of functions mapped to write to memory
78 this.memoryHighReader = []; //Array of functions mapped to read back 0xFFXX memory
79 this.memoryHighWriter = []; //Array of functions mapped to write to 0xFFXX memory
80 this.ROM = []; //The full ROM file dumped to an array.
81 this.memory = []; //Main Core Memory
82 this.MBCRam = []; //Switchable RAM (Used by games for more RAM) for the main memory range 0xA000 - 0xC000.
83 this.VRAM = []; //Extra VRAM bank for GBC.
84 this.GBCMemory = []; //GBC main RAM Banks
85 this.MBC1Mode = false; //MBC1 Type (4/32, 16/8)
86 this.MBCRAMBanksEnabled = false; //MBC RAM Access Control.
87 this.currMBCRAMBank = 0; //MBC Currently Indexed RAM Bank
88 this.currMBCRAMBankPosition = -0xA000; //MBC Position Adder;
89 this.cGBC = false; //GameBoy Color detection.
90 this.gbcRamBank = 1; //Currently Switched GameBoy Color ram bank
91 this.gbcRamBankPosition = -0xD000; //GBC RAM offset from address start.
92 this.gbcRamBankPositionECHO = -0xF000; //GBC RAM (ECHO mirroring) offset from address start.
93 this.RAMBanks = [0, 1, 2, 4, 16]; //Used to map the RAM banks to maximum size the MBC used can do.
94 this.ROMBank1offs = 0; //Offset of the ROM bank switching.
95 this.currentROMBank = 0; //The parsed current ROM bank selection.
96 this.cartridgeType = 0; //Cartridge Type
97 this.name = ""; //Name of the game
98 this.gameCode = ""; //Game code (Suffix for older games)
99 this.fromSaveState = false; //A boolean to see if this was loaded in as a save state.
100 this.savedStateFileName = ""; //When loaded in as a save state, this will not be empty.
101 this.STATTracker = 0; //Tracker for STAT triggering.
102 this.modeSTAT = 0; //The scan line mode (for lines 1-144 it's 2-3-0, for 145-154 it's 1)
103 this.spriteCount = 252; //Mode 3 extra clocking counter (Depends on how many sprites are on the current line.).
104 this.LYCMatchTriggerSTAT = false; //Should we trigger an interrupt if LY==LYC?
105 this.mode2TriggerSTAT = false; //Should we trigger an interrupt if in mode 2?
106 this.mode1TriggerSTAT = false; //Should we trigger an interrupt if in mode 1?
107 this.mode0TriggerSTAT = false; //Should we trigger an interrupt if in mode 0?
108 this.LCDisOn = false; //Is the emulated LCD controller on?
109 this.LINECONTROL = []; //Array of functions to handle each scan line we do (onscreen + offscreen)
110 this.DISPLAYOFFCONTROL = [function (parentObj) {
111 //Array of line 0 function to handle the LCD controller when it's off (Do nothing!).
113 this.LCDCONTROL = null; //Pointer to either LINECONTROL or DISPLAYOFFCONTROL.
114 this.initializeLCDController(); //Compile the LCD controller functions.
115 //RTC (Real Time Clock for MBC3):
116 this.RTCisLatched = false;
117 this.latchedSeconds = 0; //RTC latched seconds.
118 this.latchedMinutes = 0; //RTC latched minutes.
119 this.latchedHours = 0; //RTC latched hours.
120 this.latchedLDays = 0; //RTC latched lower 8-bits of the day counter.
121 this.latchedHDays = 0; //RTC latched high-bit of the day counter.
122 this.RTCSeconds = 0; //RTC seconds counter.
123 this.RTCMinutes = 0; //RTC minutes counter.
124 this.RTCHours = 0; //RTC hours counter.
125 this.RTCDays = 0; //RTC days counter.
126 this.RTCDayOverFlow = false; //Did the RTC overflow and wrap the day counter?
127 this.RTCHALT = false; //Is the RTC allowed to clock up?
134 this.audioHandle = null; //XAudioJS handle
135 this.numSamplesTotal = 0; //Length of the sound buffers.
136 this.sampleSize = 0; //Length of the sound buffer for one channel.
137 this.dutyLookup = [ //Map the duty values given to ones we can work with.
138 [false, false, false, false, false, false, false, true],
139 [true, false, false, false, false, false, false, true],
140 [true, false, false, false, false, true, true, true],
141 [false, true, true, true, true, true, true, false]
143 this.currentBuffer = []; //The audio buffer we're working on.
144 this.bufferContainAmount = 0; //Buffer maintenance metric.
145 this.LSFR15Table = null;
146 this.LSFR7Table = null;
147 this.noiseSampleTable = null;
148 this.initializeAudioStartState();
149 this.soundMasterEnabled = false; //As its name implies
150 this.channel3PCM = null; //Channel 3 adjusted sample buffer.
152 this.VinLeftChannelMasterVolume = 8; //Computed post-mixing volume.
153 this.VinRightChannelMasterVolume = 8; //Computed post-mixing volume.
154 //Channel paths enabled:
155 this.leftChannel1 = false;
156 this.leftChannel2 = false;
157 this.leftChannel3 = false;
158 this.leftChannel4 = false;
159 this.rightChannel1 = false;
160 this.rightChannel2 = false;
161 this.rightChannel3 = false;
162 this.rightChannel4 = false;
163 //Channel output level caches:
164 this.channel1currentSampleLeft = 0;
165 this.channel1currentSampleRight = 0;
166 this.channel2currentSampleLeft = 0;
167 this.channel2currentSampleRight = 0;
168 this.channel3currentSampleLeft = 0;
169 this.channel3currentSampleRight = 0;
170 this.channel4currentSampleLeft = 0;
171 this.channel4currentSampleRight = 0;
172 this.channel1currentSampleLeftSecondary = 0;
173 this.channel1currentSampleRightSecondary = 0;
174 this.channel2currentSampleLeftSecondary = 0;
175 this.channel2currentSampleRightSecondary = 0;
176 this.channel3currentSampleLeftSecondary = 0;
177 this.channel3currentSampleRightSecondary = 0;
178 this.channel4currentSampleLeftSecondary = 0;
179 this.channel4currentSampleRightSecondary = 0;
180 this.channel1currentSampleLeftTrimary = 0;
181 this.channel1currentSampleRightTrimary = 0;
182 this.channel2currentSampleLeftTrimary = 0;
183 this.channel2currentSampleRightTrimary = 0;
184 this.mixerOutputCache = 0;
185 //Pre-multipliers to cache some calculations:
186 this.initializeTiming();
187 this.machineOut = 0; //Premultiplier for audio samples per instruction.
188 //Audio generation counters:
189 this.audioTicks = 0; //Used to sample the audio system every x CPU instructions.
190 this.audioIndex = 0; //Used to keep alignment on audio generation.
191 this.rollover = 0; //Used to keep alignment on the number of samples to output (Realign from counter alias).
193 this.emulatorTicks = 0; //Times for how many instructions to execute before ending the loop.
194 this.DIVTicks = 56; //DIV Ticks Counter (Invisible lower 8-bit)
195 this.LCDTicks = 60; //Counter for how many instructions have been executed on a scanline so far.
196 this.timerTicks = 0; //Counter for the TIMA timer.
197 this.TIMAEnabled = false; //Is TIMA enabled?
198 this.TACClocker = 1024; //Timer Max Ticks
199 this.serialTimer = 0; //Serial IRQ Timer
200 this.serialShiftTimer = 0; //Serial Transfer Shift Timer
201 this.serialShiftTimerAllocated = 0; //Serial Transfer Shift Timer Refill
202 this.IRQEnableDelay = 0; //Are the interrupts on queue to be enabled?
203 var dateVar = new_Date(); // The line is changed for benchmarking.
204 this.lastIteration = dateVar.getTime();//The last time we iterated the main loop.
205 dateVar = new_Date(); // The line is changed for benchmarking.
206 this.firstIteration = dateVar.getTime();
208 this.actualScanLine = 0; //Actual scan line...
209 this.lastUnrenderedLine = 0; //Last rendered scan line...
210 this.queuedScanLines = 0;
211 this.totalLinesPassed = 0;
212 this.haltPostClocks = 0; //Post-Halt clocking.
213 //ROM Cartridge Components:
214 this.cMBC1 = false; //Does the cartridge use MBC1?
215 this.cMBC2 = false; //Does the cartridge use MBC2?
216 this.cMBC3 = false; //Does the cartridge use MBC3?
217 this.cMBC5 = false; //Does the cartridge use MBC5?
218 this.cMBC7 = false; //Does the cartridge use MBC7?
219 this.cSRAM = false; //Does the cartridge use save RAM?
220 this.cMMMO1 = false; //...
221 this.cRUMBLE = false; //Does the cartridge use the RUMBLE addressing (modified MBC5)?
222 this.cCamera = false; //Is the cartridge actually a GameBoy Camera?
223 this.cTAMA5 = false; //Does the cartridge use TAMA5? (Tamagotchi Cartridge)
224 this.cHuC3 = false; //Does the cartridge use HuC3 (Hudson Soft / modified MBC3)?
225 this.cHuC1 = false; //Does the cartridge use HuC1 (Hudson Soft / modified MBC1)?
226 this.cTIMER = false; //Does the cartridge have an RTC?
227 this.ROMBanks = [ // 1 Bank = 16 KBytes = 256 Kbits
228 2, 4, 8, 16, 32, 64, 128, 256, 512
230 this.ROMBanks[0x52] = 72;
231 this.ROMBanks[0x53] = 80;
232 this.ROMBanks[0x54] = 96;
233 this.numRAMBanks = 0; //How many RAM banks were actually allocated?
234 ////Graphics Variables
235 this.currVRAMBank = 0; //Current VRAM bank for GBC.
236 this.backgroundX = 0; //Register SCX (X-Scroll)
237 this.backgroundY = 0; //Register SCY (Y-Scroll)
238 this.gfxWindowDisplay = false; //Is the windows enabled?
239 this.gfxSpriteShow = false; //Are sprites enabled?
240 this.gfxSpriteNormalHeight = true; //Are we doing 8x8 or 8x16 sprites?
241 this.bgEnabled = true; //Is the BG enabled?
242 this.BGPriorityEnabled = true; //Can we flag the BG for priority over sprites?
243 this.gfxWindowCHRBankPosition = 0; //The current bank of the character map the window uses.
244 this.gfxBackgroundCHRBankPosition = 0; //The current bank of the character map the BG uses.
245 this.gfxBackgroundBankOffset = 0x80; //Fast mapping of the tile numbering/
246 this.windowY = 0; //Current Y offset of the window.
247 this.windowX = 0; //Current X offset of the window.
248 this.drewBlank = 0; //To prevent the repeating of drawing a blank screen.
249 this.drewFrame = false; //Throttle how many draws we can do to once per iteration.
250 this.midScanlineOffset = -1; //mid-scanline rendering offset.
251 this.pixelEnd = 0; //track the x-coord limit for line rendering (mid-scanline usage).
252 this.currentX = 0; //The x-coord we left off at for mid-scanline rendering.
253 //BG Tile Pointer Caches:
254 this.BGCHRBank1 = null;
255 this.BGCHRBank2 = null;
256 this.BGCHRCurrentBank = null;
258 this.tileCache = null;
260 this.colors = [0xEFFFDE, 0xADD794, 0x529273, 0x183442]; //"Classic" GameBoy palette colors.
261 this.OBJPalette = null;
262 this.BGPalette = null;
263 this.gbcOBJRawPalette = null;
264 this.gbcBGRawPalette = null;
265 this.gbOBJPalette = null;
266 this.gbBGPalette = null;
267 this.gbcOBJPalette = null;
268 this.gbcBGPalette = null;
269 this.gbBGColorizedPalette = null;
270 this.gbOBJColorizedPalette = null;
271 this.cachedBGPaletteConversion = null;
272 this.cachedOBJPaletteConversion = null;
273 this.updateGBBGPalette = this.updateGBRegularBGPalette;
274 this.updateGBOBJPalette = this.updateGBRegularOBJPalette;
275 this.colorizedGBPalettes = false;
276 this.BGLayerRender = null; //Reference to the BG rendering function.
277 this.WindowLayerRender = null; //Reference to the window rendering function.
278 this.SpriteLayerRender = null; //Reference to the OAM rendering function.
279 this.frameBuffer = []; //The internal frame-buffer.
280 this.swizzledFrame = null; //The secondary gfx buffer that holds the converted RGBA values.
281 this.canvasBuffer = null; //imageData handle
282 this.pixelStart = 0; //Temp variable for holding the current working framebuffer offset.
283 //Variables used for scaling in JS:
284 this.onscreenWidth = this.offscreenWidth = 160;
285 this.onscreenHeight = this.offScreenheight = 144;
286 this.offscreenRGBCount = this.onscreenWidth * this.onscreenHeight * 4;
287 //Initialize the white noise cache tables ahead of time:
288 this.intializeWhiteNoise();
291 // Start of code changed for benchmarking (removed ROM):
292 GameBoyCore.prototype.GBBOOTROM = [];
293 GameBoyCore.prototype.GBCBOOTROM = [];
294 // End of code changed for benchmarking.
296 GameBoyCore.prototype.ffxxDump = [ //Dump of the post-BOOT I/O register state (From gambatte):
297 0x0F, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
298 0x80, 0xBF, 0xF3, 0xFF, 0xBF, 0xFF, 0x3F, 0x00, 0xFF, 0xBF, 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, 0xFF,
299 0xFF, 0x00, 0x00, 0xBF, 0x77, 0xF3, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
300 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
301 0x91, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7E, 0xFF, 0xFE,
302 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
303 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xC1, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
304 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
305 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
306 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
307 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E,
308 0x45, 0xEC, 0x52, 0xFA, 0x08, 0xB7, 0x07, 0x5D, 0x01, 0xFD, 0xC0, 0xFF, 0x08, 0xFC, 0x00, 0xE5,
309 0x0B, 0xF8, 0xC2, 0xCE, 0xF4, 0xF9, 0x0F, 0x7F, 0x45, 0x6D, 0x3D, 0xFE, 0x46, 0x97, 0x33, 0x5E,
310 0x08, 0xEF, 0xF1, 0xFF, 0x86, 0x83, 0x24, 0x74, 0x12, 0xFC, 0x00, 0x9F, 0xB4, 0xB7, 0x06, 0xD5,
311 0xD0, 0x7A, 0x00, 0x9E, 0x04, 0x5F, 0x41, 0x2F, 0x1D, 0x77, 0x36, 0x75, 0x81, 0xAA, 0x70, 0x3A,
312 0x98, 0xD1, 0x71, 0x02, 0x4D, 0x01, 0xC1, 0xFF, 0x0D, 0x00, 0xD3, 0x05, 0xF9, 0x00, 0x0B, 0x00
314 GameBoyCore.prototype.OPCODE = [
317 function (parentObj) {
322 function (parentObj) {
323 parentObj.registerC = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
324 parentObj.registerB = parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF);
325 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
329 function (parentObj) {
330 parentObj.memoryWrite((parentObj.registerB << 8) | parentObj.registerC, parentObj.registerA);
334 function (parentObj) {
335 var temp_var = ((parentObj.registerB << 8) | parentObj.registerC) + 1;
336 parentObj.registerB = (temp_var >> 8) & 0xFF;
337 parentObj.registerC = temp_var & 0xFF;
341 function (parentObj) {
342 parentObj.registerB = (parentObj.registerB + 1) & 0xFF;
343 parentObj.FZero = (parentObj.registerB == 0);
344 parentObj.FHalfCarry = ((parentObj.registerB & 0xF) == 0);
345 parentObj.FSubtract = false;
349 function (parentObj) {
350 parentObj.registerB = (parentObj.registerB - 1) & 0xFF;
351 parentObj.FZero = (parentObj.registerB == 0);
352 parentObj.FHalfCarry = ((parentObj.registerB & 0xF) == 0xF);
353 parentObj.FSubtract = true;
357 function (parentObj) {
358 parentObj.registerB = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
359 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
363 function (parentObj) {
364 parentObj.FCarry = (parentObj.registerA > 0x7F);
365 parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | (parentObj.registerA >> 7);
366 parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
370 function (parentObj) {
371 var temp_var = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
372 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
373 parentObj.memoryWrite(temp_var, parentObj.stackPointer & 0xFF);
374 parentObj.memoryWrite((temp_var + 1) & 0xFFFF, parentObj.stackPointer >> 8);
378 function (parentObj) {
379 var dirtySum = parentObj.registersHL + ((parentObj.registerB << 8) | parentObj.registerC);
380 parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > (dirtySum & 0xFFF));
381 parentObj.FCarry = (dirtySum > 0xFFFF);
382 parentObj.registersHL = dirtySum & 0xFFFF;
383 parentObj.FSubtract = false;
387 function (parentObj) {
388 parentObj.registerA = parentObj.memoryRead((parentObj.registerB << 8) | parentObj.registerC);
392 function (parentObj) {
393 var temp_var = (((parentObj.registerB << 8) | parentObj.registerC) - 1) & 0xFFFF;
394 parentObj.registerB = temp_var >> 8;
395 parentObj.registerC = temp_var & 0xFF;
399 function (parentObj) {
400 parentObj.registerC = (parentObj.registerC + 1) & 0xFF;
401 parentObj.FZero = (parentObj.registerC == 0);
402 parentObj.FHalfCarry = ((parentObj.registerC & 0xF) == 0);
403 parentObj.FSubtract = false;
407 function (parentObj) {
408 parentObj.registerC = (parentObj.registerC - 1) & 0xFF;
409 parentObj.FZero = (parentObj.registerC == 0);
410 parentObj.FHalfCarry = ((parentObj.registerC & 0xF) == 0xF);
411 parentObj.FSubtract = true;
415 function (parentObj) {
416 parentObj.registerC = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
417 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
421 function (parentObj) {
422 parentObj.registerA = (parentObj.registerA >> 1) | ((parentObj.registerA & 1) << 7);
423 parentObj.FCarry = (parentObj.registerA > 0x7F);
424 parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
428 function (parentObj) {
429 if (parentObj.cGBC) {
430 if ((parentObj.memory[0xFF4D] & 0x01) == 0x01) { //Speed change requested.
431 if (parentObj.memory[0xFF4D] > 0x7F) { //Go back to single speed mode.
432 cout("Going into single clock speed mode.", 0);
433 parentObj.doubleSpeedShifter = 0;
434 parentObj.memory[0xFF4D] &= 0x7F; //Clear the double speed mode flag.
436 else { //Go to double speed mode.
437 cout("Going into double clock speed mode.", 0);
438 parentObj.doubleSpeedShifter = 1;
439 parentObj.memory[0xFF4D] |= 0x80; //Set the double speed mode flag.
441 parentObj.memory[0xFF4D] &= 0xFE; //Reset the request bit.
444 parentObj.handleSTOP();
448 parentObj.handleSTOP();
453 function (parentObj) {
454 parentObj.registerE = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
455 parentObj.registerD = parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF);
456 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
460 function (parentObj) {
461 parentObj.memoryWrite((parentObj.registerD << 8) | parentObj.registerE, parentObj.registerA);
465 function (parentObj) {
466 var temp_var = ((parentObj.registerD << 8) | parentObj.registerE) + 1;
467 parentObj.registerD = (temp_var >> 8) & 0xFF;
468 parentObj.registerE = temp_var & 0xFF;
472 function (parentObj) {
473 parentObj.registerD = (parentObj.registerD + 1) & 0xFF;
474 parentObj.FZero = (parentObj.registerD == 0);
475 parentObj.FHalfCarry = ((parentObj.registerD & 0xF) == 0);
476 parentObj.FSubtract = false;
480 function (parentObj) {
481 parentObj.registerD = (parentObj.registerD - 1) & 0xFF;
482 parentObj.FZero = (parentObj.registerD == 0);
483 parentObj.FHalfCarry = ((parentObj.registerD & 0xF) == 0xF);
484 parentObj.FSubtract = true;
488 function (parentObj) {
489 parentObj.registerD = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
490 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
494 function (parentObj) {
495 var carry_flag = (parentObj.FCarry) ? 1 : 0;
496 parentObj.FCarry = (parentObj.registerA > 0x7F);
497 parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | carry_flag;
498 parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
502 function (parentObj) {
503 parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
507 function (parentObj) {
508 var dirtySum = parentObj.registersHL + ((parentObj.registerD << 8) | parentObj.registerE);
509 parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > (dirtySum & 0xFFF));
510 parentObj.FCarry = (dirtySum > 0xFFFF);
511 parentObj.registersHL = dirtySum & 0xFFFF;
512 parentObj.FSubtract = false;
516 function (parentObj) {
517 parentObj.registerA = parentObj.memoryRead((parentObj.registerD << 8) | parentObj.registerE);
521 function (parentObj) {
522 var temp_var = (((parentObj.registerD << 8) | parentObj.registerE) - 1) & 0xFFFF;
523 parentObj.registerD = temp_var >> 8;
524 parentObj.registerE = temp_var & 0xFF;
528 function (parentObj) {
529 parentObj.registerE = (parentObj.registerE + 1) & 0xFF;
530 parentObj.FZero = (parentObj.registerE == 0);
531 parentObj.FHalfCarry = ((parentObj.registerE & 0xF) == 0);
532 parentObj.FSubtract = false;
536 function (parentObj) {
537 parentObj.registerE = (parentObj.registerE - 1) & 0xFF;
538 parentObj.FZero = (parentObj.registerE == 0);
539 parentObj.FHalfCarry = ((parentObj.registerE & 0xF) == 0xF);
540 parentObj.FSubtract = true;
544 function (parentObj) {
545 parentObj.registerE = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
546 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
550 function (parentObj) {
551 var carry_flag = (parentObj.FCarry) ? 0x80 : 0;
552 parentObj.FCarry = ((parentObj.registerA & 1) == 1);
553 parentObj.registerA = (parentObj.registerA >> 1) | carry_flag;
554 parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
558 function (parentObj) {
559 if (!parentObj.FZero) {
560 parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
561 parentObj.CPUTicks += 4;
564 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
569 function (parentObj) {
570 parentObj.registersHL = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
571 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
575 function (parentObj) {
576 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerA);
577 parentObj.registersHL = (parentObj.registersHL + 1) & 0xFFFF;
581 function (parentObj) {
582 parentObj.registersHL = (parentObj.registersHL + 1) & 0xFFFF;
586 function (parentObj) {
587 var H = ((parentObj.registersHL >> 8) + 1) & 0xFF;
588 parentObj.FZero = (H == 0);
589 parentObj.FHalfCarry = ((H & 0xF) == 0);
590 parentObj.FSubtract = false;
591 parentObj.registersHL = (H << 8) | (parentObj.registersHL & 0xFF);
595 function (parentObj) {
596 var H = ((parentObj.registersHL >> 8) - 1) & 0xFF;
597 parentObj.FZero = (H == 0);
598 parentObj.FHalfCarry = ((H & 0xF) == 0xF);
599 parentObj.FSubtract = true;
600 parentObj.registersHL = (H << 8) | (parentObj.registersHL & 0xFF);
604 function (parentObj) {
605 parentObj.registersHL = (parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 8) | (parentObj.registersHL & 0xFF);
606 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
610 function (parentObj) {
611 if (!parentObj.FSubtract) {
612 if (parentObj.FCarry || parentObj.registerA > 0x99) {
613 parentObj.registerA = (parentObj.registerA + 0x60) & 0xFF;
614 parentObj.FCarry = true;
616 if (parentObj.FHalfCarry || (parentObj.registerA & 0xF) > 0x9) {
617 parentObj.registerA = (parentObj.registerA + 0x06) & 0xFF;
618 parentObj.FHalfCarry = false;
621 else if (parentObj.FCarry && parentObj.FHalfCarry) {
622 parentObj.registerA = (parentObj.registerA + 0x9A) & 0xFF;
623 parentObj.FHalfCarry = false;
625 else if (parentObj.FCarry) {
626 parentObj.registerA = (parentObj.registerA + 0xA0) & 0xFF;
628 else if (parentObj.FHalfCarry) {
629 parentObj.registerA = (parentObj.registerA + 0xFA) & 0xFF;
630 parentObj.FHalfCarry = false;
632 parentObj.FZero = (parentObj.registerA == 0);
636 function (parentObj) {
637 if (parentObj.FZero) {
638 parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
639 parentObj.CPUTicks += 4;
642 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
647 function (parentObj) {
648 parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > 0x7FF);
649 parentObj.FCarry = (parentObj.registersHL > 0x7FFF);
650 parentObj.registersHL = (parentObj.registersHL << 1) & 0xFFFF;
651 parentObj.FSubtract = false;
655 function (parentObj) {
656 parentObj.registerA = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
657 parentObj.registersHL = (parentObj.registersHL + 1) & 0xFFFF;
661 function (parentObj) {
662 parentObj.registersHL = (parentObj.registersHL - 1) & 0xFFFF;
666 function (parentObj) {
667 var L = (parentObj.registersHL + 1) & 0xFF;
668 parentObj.FZero = (L == 0);
669 parentObj.FHalfCarry = ((L & 0xF) == 0);
670 parentObj.FSubtract = false;
671 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | L;
675 function (parentObj) {
676 var L = (parentObj.registersHL - 1) & 0xFF;
677 parentObj.FZero = (L == 0);
678 parentObj.FHalfCarry = ((L & 0xF) == 0xF);
679 parentObj.FSubtract = true;
680 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | L;
684 function (parentObj) {
685 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
686 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
690 function (parentObj) {
691 parentObj.registerA ^= 0xFF;
692 parentObj.FSubtract = parentObj.FHalfCarry = true;
696 function (parentObj) {
697 if (!parentObj.FCarry) {
698 parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
699 parentObj.CPUTicks += 4;
702 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
707 function (parentObj) {
708 parentObj.stackPointer = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
709 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
713 function (parentObj) {
714 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerA);
715 parentObj.registersHL = (parentObj.registersHL - 1) & 0xFFFF;
719 function (parentObj) {
720 parentObj.stackPointer = (parentObj.stackPointer + 1) & 0xFFFF;
724 function (parentObj) {
725 var temp_var = (parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) + 1) & 0xFF;
726 parentObj.FZero = (temp_var == 0);
727 parentObj.FHalfCarry = ((temp_var & 0xF) == 0);
728 parentObj.FSubtract = false;
729 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
733 function (parentObj) {
734 var temp_var = (parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) - 1) & 0xFF;
735 parentObj.FZero = (temp_var == 0);
736 parentObj.FHalfCarry = ((temp_var & 0xF) == 0xF);
737 parentObj.FSubtract = true;
738 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
742 function (parentObj) {
743 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter));
744 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
748 function (parentObj) {
749 parentObj.FCarry = true;
750 parentObj.FSubtract = parentObj.FHalfCarry = false;
754 function (parentObj) {
755 if (parentObj.FCarry) {
756 parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
757 parentObj.CPUTicks += 4;
760 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
765 function (parentObj) {
766 var dirtySum = parentObj.registersHL + parentObj.stackPointer;
767 parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > (dirtySum & 0xFFF));
768 parentObj.FCarry = (dirtySum > 0xFFFF);
769 parentObj.registersHL = dirtySum & 0xFFFF;
770 parentObj.FSubtract = false;
774 function (parentObj) {
775 parentObj.registerA = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
776 parentObj.registersHL = (parentObj.registersHL - 1) & 0xFFFF;
780 function (parentObj) {
781 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
785 function (parentObj) {
786 parentObj.registerA = (parentObj.registerA + 1) & 0xFF;
787 parentObj.FZero = (parentObj.registerA == 0);
788 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) == 0);
789 parentObj.FSubtract = false;
793 function (parentObj) {
794 parentObj.registerA = (parentObj.registerA - 1) & 0xFF;
795 parentObj.FZero = (parentObj.registerA == 0);
796 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) == 0xF);
797 parentObj.FSubtract = true;
801 function (parentObj) {
802 parentObj.registerA = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
803 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
807 function (parentObj) {
808 parentObj.FCarry = !parentObj.FCarry;
809 parentObj.FSubtract = parentObj.FHalfCarry = false;
813 function (parentObj) {
818 function (parentObj) {
819 parentObj.registerB = parentObj.registerC;
823 function (parentObj) {
824 parentObj.registerB = parentObj.registerD;
828 function (parentObj) {
829 parentObj.registerB = parentObj.registerE;
833 function (parentObj) {
834 parentObj.registerB = parentObj.registersHL >> 8;
838 function (parentObj) {
839 parentObj.registerB = parentObj.registersHL & 0xFF;
843 function (parentObj) {
844 parentObj.registerB = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
848 function (parentObj) {
849 parentObj.registerB = parentObj.registerA;
853 function (parentObj) {
854 parentObj.registerC = parentObj.registerB;
858 function (parentObj) {
863 function (parentObj) {
864 parentObj.registerC = parentObj.registerD;
868 function (parentObj) {
869 parentObj.registerC = parentObj.registerE;
873 function (parentObj) {
874 parentObj.registerC = parentObj.registersHL >> 8;
878 function (parentObj) {
879 parentObj.registerC = parentObj.registersHL & 0xFF;
883 function (parentObj) {
884 parentObj.registerC = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
888 function (parentObj) {
889 parentObj.registerC = parentObj.registerA;
893 function (parentObj) {
894 parentObj.registerD = parentObj.registerB;
898 function (parentObj) {
899 parentObj.registerD = parentObj.registerC;
903 function (parentObj) {
908 function (parentObj) {
909 parentObj.registerD = parentObj.registerE;
913 function (parentObj) {
914 parentObj.registerD = parentObj.registersHL >> 8;
918 function (parentObj) {
919 parentObj.registerD = parentObj.registersHL & 0xFF;
923 function (parentObj) {
924 parentObj.registerD = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
928 function (parentObj) {
929 parentObj.registerD = parentObj.registerA;
933 function (parentObj) {
934 parentObj.registerE = parentObj.registerB;
938 function (parentObj) {
939 parentObj.registerE = parentObj.registerC;
943 function (parentObj) {
944 parentObj.registerE = parentObj.registerD;
948 function (parentObj) {
953 function (parentObj) {
954 parentObj.registerE = parentObj.registersHL >> 8;
958 function (parentObj) {
959 parentObj.registerE = parentObj.registersHL & 0xFF;
963 function (parentObj) {
964 parentObj.registerE = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
968 function (parentObj) {
969 parentObj.registerE = parentObj.registerA;
973 function (parentObj) {
974 parentObj.registersHL = (parentObj.registerB << 8) | (parentObj.registersHL & 0xFF);
978 function (parentObj) {
979 parentObj.registersHL = (parentObj.registerC << 8) | (parentObj.registersHL & 0xFF);
983 function (parentObj) {
984 parentObj.registersHL = (parentObj.registerD << 8) | (parentObj.registersHL & 0xFF);
988 function (parentObj) {
989 parentObj.registersHL = (parentObj.registerE << 8) | (parentObj.registersHL & 0xFF);
993 function (parentObj) {
998 function (parentObj) {
999 parentObj.registersHL = (parentObj.registersHL & 0xFF) * 0x101;
1003 function (parentObj) {
1004 parentObj.registersHL = (parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) << 8) | (parentObj.registersHL & 0xFF);
1008 function (parentObj) {
1009 parentObj.registersHL = (parentObj.registerA << 8) | (parentObj.registersHL & 0xFF);
1013 function (parentObj) {
1014 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerB;
1018 function (parentObj) {
1019 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerC;
1023 function (parentObj) {
1024 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerD;
1028 function (parentObj) {
1029 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerE;
1033 function (parentObj) {
1034 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | (parentObj.registersHL >> 8);
1038 function (parentObj) {
1043 function (parentObj) {
1044 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1048 function (parentObj) {
1049 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerA;
1053 function (parentObj) {
1054 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerB);
1058 function (parentObj) {
1059 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerC);
1063 function (parentObj) {
1064 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerD);
1068 function (parentObj) {
1069 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerE);
1073 function (parentObj) {
1074 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registersHL >> 8);
1078 function (parentObj) {
1079 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registersHL & 0xFF);
1083 function (parentObj) {
1084 //See if there's already an IRQ match:
1085 if ((parentObj.interruptsEnabled & parentObj.interruptsRequested & 0x1F) > 0) {
1086 if (!parentObj.cGBC && !parentObj.usedBootROM) {
1087 //HALT bug in the DMG CPU model (Program Counter fails to increment for one instruction after HALT):
1088 parentObj.skipPCIncrement = true;
1091 //CGB gets around the HALT PC bug by doubling the hidden NOP.
1092 parentObj.CPUTicks += 4;
1096 //CPU is stalled until the next IRQ match:
1097 parentObj.calculateHALTPeriod();
1102 function (parentObj) {
1103 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerA);
1107 function (parentObj) {
1108 parentObj.registerA = parentObj.registerB;
1112 function (parentObj) {
1113 parentObj.registerA = parentObj.registerC;
1117 function (parentObj) {
1118 parentObj.registerA = parentObj.registerD;
1122 function (parentObj) {
1123 parentObj.registerA = parentObj.registerE;
1127 function (parentObj) {
1128 parentObj.registerA = parentObj.registersHL >> 8;
1132 function (parentObj) {
1133 parentObj.registerA = parentObj.registersHL & 0xFF;
1137 function (parentObj) {
1138 parentObj.registerA = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1142 function (parentObj) {
1147 function (parentObj) {
1148 var dirtySum = parentObj.registerA + parentObj.registerB;
1149 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1150 parentObj.FCarry = (dirtySum > 0xFF);
1151 parentObj.registerA = dirtySum & 0xFF;
1152 parentObj.FZero = (parentObj.registerA == 0);
1153 parentObj.FSubtract = false;
1157 function (parentObj) {
1158 var dirtySum = parentObj.registerA + parentObj.registerC;
1159 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1160 parentObj.FCarry = (dirtySum > 0xFF);
1161 parentObj.registerA = dirtySum & 0xFF;
1162 parentObj.FZero = (parentObj.registerA == 0);
1163 parentObj.FSubtract = false;
1167 function (parentObj) {
1168 var dirtySum = parentObj.registerA + parentObj.registerD;
1169 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1170 parentObj.FCarry = (dirtySum > 0xFF);
1171 parentObj.registerA = dirtySum & 0xFF;
1172 parentObj.FZero = (parentObj.registerA == 0);
1173 parentObj.FSubtract = false;
1177 function (parentObj) {
1178 var dirtySum = parentObj.registerA + parentObj.registerE;
1179 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1180 parentObj.FCarry = (dirtySum > 0xFF);
1181 parentObj.registerA = dirtySum & 0xFF;
1182 parentObj.FZero = (parentObj.registerA == 0);
1183 parentObj.FSubtract = false;
1187 function (parentObj) {
1188 var dirtySum = parentObj.registerA + (parentObj.registersHL >> 8);
1189 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1190 parentObj.FCarry = (dirtySum > 0xFF);
1191 parentObj.registerA = dirtySum & 0xFF;
1192 parentObj.FZero = (parentObj.registerA == 0);
1193 parentObj.FSubtract = false;
1197 function (parentObj) {
1198 var dirtySum = parentObj.registerA + (parentObj.registersHL & 0xFF);
1199 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1200 parentObj.FCarry = (dirtySum > 0xFF);
1201 parentObj.registerA = dirtySum & 0xFF;
1202 parentObj.FZero = (parentObj.registerA == 0);
1203 parentObj.FSubtract = false;
1207 function (parentObj) {
1208 var dirtySum = parentObj.registerA + parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1209 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1210 parentObj.FCarry = (dirtySum > 0xFF);
1211 parentObj.registerA = dirtySum & 0xFF;
1212 parentObj.FZero = (parentObj.registerA == 0);
1213 parentObj.FSubtract = false;
1217 function (parentObj) {
1218 parentObj.FHalfCarry = ((parentObj.registerA & 0x8) == 0x8);
1219 parentObj.FCarry = (parentObj.registerA > 0x7F);
1220 parentObj.registerA = (parentObj.registerA << 1) & 0xFF;
1221 parentObj.FZero = (parentObj.registerA == 0);
1222 parentObj.FSubtract = false;
1226 function (parentObj) {
1227 var dirtySum = parentObj.registerA + parentObj.registerB + ((parentObj.FCarry) ? 1 : 0);
1228 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerB & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1229 parentObj.FCarry = (dirtySum > 0xFF);
1230 parentObj.registerA = dirtySum & 0xFF;
1231 parentObj.FZero = (parentObj.registerA == 0);
1232 parentObj.FSubtract = false;
1236 function (parentObj) {
1237 var dirtySum = parentObj.registerA + parentObj.registerC + ((parentObj.FCarry) ? 1 : 0);
1238 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerC & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1239 parentObj.FCarry = (dirtySum > 0xFF);
1240 parentObj.registerA = dirtySum & 0xFF;
1241 parentObj.FZero = (parentObj.registerA == 0);
1242 parentObj.FSubtract = false;
1246 function (parentObj) {
1247 var dirtySum = parentObj.registerA + parentObj.registerD + ((parentObj.FCarry) ? 1 : 0);
1248 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerD & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1249 parentObj.FCarry = (dirtySum > 0xFF);
1250 parentObj.registerA = dirtySum & 0xFF;
1251 parentObj.FZero = (parentObj.registerA == 0);
1252 parentObj.FSubtract = false;
1256 function (parentObj) {
1257 var dirtySum = parentObj.registerA + parentObj.registerE + ((parentObj.FCarry) ? 1 : 0);
1258 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerE & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1259 parentObj.FCarry = (dirtySum > 0xFF);
1260 parentObj.registerA = dirtySum & 0xFF;
1261 parentObj.FZero = (parentObj.registerA == 0);
1262 parentObj.FSubtract = false;
1266 function (parentObj) {
1267 var tempValue = (parentObj.registersHL >> 8);
1268 var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
1269 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1270 parentObj.FCarry = (dirtySum > 0xFF);
1271 parentObj.registerA = dirtySum & 0xFF;
1272 parentObj.FZero = (parentObj.registerA == 0);
1273 parentObj.FSubtract = false;
1277 function (parentObj) {
1278 var tempValue = (parentObj.registersHL & 0xFF);
1279 var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
1280 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1281 parentObj.FCarry = (dirtySum > 0xFF);
1282 parentObj.registerA = dirtySum & 0xFF;
1283 parentObj.FZero = (parentObj.registerA == 0);
1284 parentObj.FSubtract = false;
1288 function (parentObj) {
1289 var tempValue = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1290 var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
1291 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1292 parentObj.FCarry = (dirtySum > 0xFF);
1293 parentObj.registerA = dirtySum & 0xFF;
1294 parentObj.FZero = (parentObj.registerA == 0);
1295 parentObj.FSubtract = false;
1299 function (parentObj) {
1300 //shift left register A one bit for some ops here as an optimization:
1301 var dirtySum = (parentObj.registerA << 1) | ((parentObj.FCarry) ? 1 : 0);
1302 parentObj.FHalfCarry = ((((parentObj.registerA << 1) & 0x1E) | ((parentObj.FCarry) ? 1 : 0)) > 0xF);
1303 parentObj.FCarry = (dirtySum > 0xFF);
1304 parentObj.registerA = dirtySum & 0xFF;
1305 parentObj.FZero = (parentObj.registerA == 0);
1306 parentObj.FSubtract = false;
1310 function (parentObj) {
1311 var dirtySum = parentObj.registerA - parentObj.registerB;
1312 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1313 parentObj.FCarry = (dirtySum < 0);
1314 parentObj.registerA = dirtySum & 0xFF;
1315 parentObj.FZero = (dirtySum == 0);
1316 parentObj.FSubtract = true;
1320 function (parentObj) {
1321 var dirtySum = parentObj.registerA - parentObj.registerC;
1322 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1323 parentObj.FCarry = (dirtySum < 0);
1324 parentObj.registerA = dirtySum & 0xFF;
1325 parentObj.FZero = (dirtySum == 0);
1326 parentObj.FSubtract = true;
1330 function (parentObj) {
1331 var dirtySum = parentObj.registerA - parentObj.registerD;
1332 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1333 parentObj.FCarry = (dirtySum < 0);
1334 parentObj.registerA = dirtySum & 0xFF;
1335 parentObj.FZero = (dirtySum == 0);
1336 parentObj.FSubtract = true;
1340 function (parentObj) {
1341 var dirtySum = parentObj.registerA - parentObj.registerE;
1342 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1343 parentObj.FCarry = (dirtySum < 0);
1344 parentObj.registerA = dirtySum & 0xFF;
1345 parentObj.FZero = (dirtySum == 0);
1346 parentObj.FSubtract = true;
1350 function (parentObj) {
1351 var dirtySum = parentObj.registerA - (parentObj.registersHL >> 8);
1352 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1353 parentObj.FCarry = (dirtySum < 0);
1354 parentObj.registerA = dirtySum & 0xFF;
1355 parentObj.FZero = (dirtySum == 0);
1356 parentObj.FSubtract = true;
1360 function (parentObj) {
1361 var dirtySum = parentObj.registerA - (parentObj.registersHL & 0xFF);
1362 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1363 parentObj.FCarry = (dirtySum < 0);
1364 parentObj.registerA = dirtySum & 0xFF;
1365 parentObj.FZero = (dirtySum == 0);
1366 parentObj.FSubtract = true;
1370 function (parentObj) {
1371 var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1372 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1373 parentObj.FCarry = (dirtySum < 0);
1374 parentObj.registerA = dirtySum & 0xFF;
1375 parentObj.FZero = (dirtySum == 0);
1376 parentObj.FSubtract = true;
1380 function (parentObj) {
1381 //number - same number == 0
1382 parentObj.registerA = 0;
1383 parentObj.FHalfCarry = parentObj.FCarry = false;
1384 parentObj.FZero = parentObj.FSubtract = true;
1388 function (parentObj) {
1389 var dirtySum = parentObj.registerA - parentObj.registerB - ((parentObj.FCarry) ? 1 : 0);
1390 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerB & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1391 parentObj.FCarry = (dirtySum < 0);
1392 parentObj.registerA = dirtySum & 0xFF;
1393 parentObj.FZero = (parentObj.registerA == 0);
1394 parentObj.FSubtract = true;
1398 function (parentObj) {
1399 var dirtySum = parentObj.registerA - parentObj.registerC - ((parentObj.FCarry) ? 1 : 0);
1400 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerC & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1401 parentObj.FCarry = (dirtySum < 0);
1402 parentObj.registerA = dirtySum & 0xFF;
1403 parentObj.FZero = (parentObj.registerA == 0);
1404 parentObj.FSubtract = true;
1408 function (parentObj) {
1409 var dirtySum = parentObj.registerA - parentObj.registerD - ((parentObj.FCarry) ? 1 : 0);
1410 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerD & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1411 parentObj.FCarry = (dirtySum < 0);
1412 parentObj.registerA = dirtySum & 0xFF;
1413 parentObj.FZero = (parentObj.registerA == 0);
1414 parentObj.FSubtract = true;
1418 function (parentObj) {
1419 var dirtySum = parentObj.registerA - parentObj.registerE - ((parentObj.FCarry) ? 1 : 0);
1420 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerE & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1421 parentObj.FCarry = (dirtySum < 0);
1422 parentObj.registerA = dirtySum & 0xFF;
1423 parentObj.FZero = (parentObj.registerA == 0);
1424 parentObj.FSubtract = true;
1428 function (parentObj) {
1429 var temp_var = parentObj.registersHL >> 8;
1430 var dirtySum = parentObj.registerA - temp_var - ((parentObj.FCarry) ? 1 : 0);
1431 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (temp_var & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1432 parentObj.FCarry = (dirtySum < 0);
1433 parentObj.registerA = dirtySum & 0xFF;
1434 parentObj.FZero = (parentObj.registerA == 0);
1435 parentObj.FSubtract = true;
1439 function (parentObj) {
1440 var dirtySum = parentObj.registerA - (parentObj.registersHL & 0xFF) - ((parentObj.FCarry) ? 1 : 0);
1441 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registersHL & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1442 parentObj.FCarry = (dirtySum < 0);
1443 parentObj.registerA = dirtySum & 0xFF;
1444 parentObj.FZero = (parentObj.registerA == 0);
1445 parentObj.FSubtract = true;
1449 function (parentObj) {
1450 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1451 var dirtySum = parentObj.registerA - temp_var - ((parentObj.FCarry) ? 1 : 0);
1452 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (temp_var & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
1453 parentObj.FCarry = (dirtySum < 0);
1454 parentObj.registerA = dirtySum & 0xFF;
1455 parentObj.FZero = (parentObj.registerA == 0);
1456 parentObj.FSubtract = true;
1460 function (parentObj) {
1462 if (parentObj.FCarry) {
1463 parentObj.FZero = false;
1464 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = true;
1465 parentObj.registerA = 0xFF;
1468 parentObj.FHalfCarry = parentObj.FCarry = false;
1469 parentObj.FSubtract = parentObj.FZero = true;
1470 parentObj.registerA = 0;
1475 function (parentObj) {
1476 parentObj.registerA &= parentObj.registerB;
1477 parentObj.FZero = (parentObj.registerA == 0);
1478 parentObj.FHalfCarry = true;
1479 parentObj.FSubtract = parentObj.FCarry = false;
1483 function (parentObj) {
1484 parentObj.registerA &= parentObj.registerC;
1485 parentObj.FZero = (parentObj.registerA == 0);
1486 parentObj.FHalfCarry = true;
1487 parentObj.FSubtract = parentObj.FCarry = false;
1491 function (parentObj) {
1492 parentObj.registerA &= parentObj.registerD;
1493 parentObj.FZero = (parentObj.registerA == 0);
1494 parentObj.FHalfCarry = true;
1495 parentObj.FSubtract = parentObj.FCarry = false;
1499 function (parentObj) {
1500 parentObj.registerA &= parentObj.registerE;
1501 parentObj.FZero = (parentObj.registerA == 0);
1502 parentObj.FHalfCarry = true;
1503 parentObj.FSubtract = parentObj.FCarry = false;
1507 function (parentObj) {
1508 parentObj.registerA &= (parentObj.registersHL >> 8);
1509 parentObj.FZero = (parentObj.registerA == 0);
1510 parentObj.FHalfCarry = true;
1511 parentObj.FSubtract = parentObj.FCarry = false;
1515 function (parentObj) {
1516 parentObj.registerA &= parentObj.registersHL;
1517 parentObj.FZero = (parentObj.registerA == 0);
1518 parentObj.FHalfCarry = true;
1519 parentObj.FSubtract = parentObj.FCarry = false;
1523 function (parentObj) {
1524 parentObj.registerA &= parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1525 parentObj.FZero = (parentObj.registerA == 0);
1526 parentObj.FHalfCarry = true;
1527 parentObj.FSubtract = parentObj.FCarry = false;
1531 function (parentObj) {
1532 //number & same number = same number
1533 parentObj.FZero = (parentObj.registerA == 0);
1534 parentObj.FHalfCarry = true;
1535 parentObj.FSubtract = parentObj.FCarry = false;
1539 function (parentObj) {
1540 parentObj.registerA ^= parentObj.registerB;
1541 parentObj.FZero = (parentObj.registerA == 0);
1542 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1546 function (parentObj) {
1547 parentObj.registerA ^= parentObj.registerC;
1548 parentObj.FZero = (parentObj.registerA == 0);
1549 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1553 function (parentObj) {
1554 parentObj.registerA ^= parentObj.registerD;
1555 parentObj.FZero = (parentObj.registerA == 0);
1556 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1560 function (parentObj) {
1561 parentObj.registerA ^= parentObj.registerE;
1562 parentObj.FZero = (parentObj.registerA == 0);
1563 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1567 function (parentObj) {
1568 parentObj.registerA ^= (parentObj.registersHL >> 8);
1569 parentObj.FZero = (parentObj.registerA == 0);
1570 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1574 function (parentObj) {
1575 parentObj.registerA ^= (parentObj.registersHL & 0xFF);
1576 parentObj.FZero = (parentObj.registerA == 0);
1577 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1581 function (parentObj) {
1582 parentObj.registerA ^= parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1583 parentObj.FZero = (parentObj.registerA == 0);
1584 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1588 function (parentObj) {
1589 //number ^ same number == 0
1590 parentObj.registerA = 0;
1591 parentObj.FZero = true;
1592 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
1596 function (parentObj) {
1597 parentObj.registerA |= parentObj.registerB;
1598 parentObj.FZero = (parentObj.registerA == 0);
1599 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1603 function (parentObj) {
1604 parentObj.registerA |= parentObj.registerC;
1605 parentObj.FZero = (parentObj.registerA == 0);
1606 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1610 function (parentObj) {
1611 parentObj.registerA |= parentObj.registerD;
1612 parentObj.FZero = (parentObj.registerA == 0);
1613 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1617 function (parentObj) {
1618 parentObj.registerA |= parentObj.registerE;
1619 parentObj.FZero = (parentObj.registerA == 0);
1620 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1624 function (parentObj) {
1625 parentObj.registerA |= (parentObj.registersHL >> 8);
1626 parentObj.FZero = (parentObj.registerA == 0);
1627 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1631 function (parentObj) {
1632 parentObj.registerA |= (parentObj.registersHL & 0xFF);
1633 parentObj.FZero = (parentObj.registerA == 0);
1634 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1638 function (parentObj) {
1639 parentObj.registerA |= parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1640 parentObj.FZero = (parentObj.registerA == 0);
1641 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1645 function (parentObj) {
1646 //number | same number == same number
1647 parentObj.FZero = (parentObj.registerA == 0);
1648 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
1652 function (parentObj) {
1653 var dirtySum = parentObj.registerA - parentObj.registerB;
1654 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1655 parentObj.FCarry = (dirtySum < 0);
1656 parentObj.FZero = (dirtySum == 0);
1657 parentObj.FSubtract = true;
1661 function (parentObj) {
1662 var dirtySum = parentObj.registerA - parentObj.registerC;
1663 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1664 parentObj.FCarry = (dirtySum < 0);
1665 parentObj.FZero = (dirtySum == 0);
1666 parentObj.FSubtract = true;
1670 function (parentObj) {
1671 var dirtySum = parentObj.registerA - parentObj.registerD;
1672 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1673 parentObj.FCarry = (dirtySum < 0);
1674 parentObj.FZero = (dirtySum == 0);
1675 parentObj.FSubtract = true;
1679 function (parentObj) {
1680 var dirtySum = parentObj.registerA - parentObj.registerE;
1681 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1682 parentObj.FCarry = (dirtySum < 0);
1683 parentObj.FZero = (dirtySum == 0);
1684 parentObj.FSubtract = true;
1688 function (parentObj) {
1689 var dirtySum = parentObj.registerA - (parentObj.registersHL >> 8);
1690 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1691 parentObj.FCarry = (dirtySum < 0);
1692 parentObj.FZero = (dirtySum == 0);
1693 parentObj.FSubtract = true;
1697 function (parentObj) {
1698 var dirtySum = parentObj.registerA - (parentObj.registersHL & 0xFF);
1699 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1700 parentObj.FCarry = (dirtySum < 0);
1701 parentObj.FZero = (dirtySum == 0);
1702 parentObj.FSubtract = true;
1706 function (parentObj) {
1707 var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
1708 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
1709 parentObj.FCarry = (dirtySum < 0);
1710 parentObj.FZero = (dirtySum == 0);
1711 parentObj.FSubtract = true;
1715 function (parentObj) {
1716 parentObj.FHalfCarry = parentObj.FCarry = false;
1717 parentObj.FZero = parentObj.FSubtract = true;
1721 function (parentObj) {
1722 if (!parentObj.FZero) {
1723 parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1724 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1725 parentObj.CPUTicks += 12;
1730 function (parentObj) {
1731 parentObj.registerC = parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1732 parentObj.registerB = parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF);
1733 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1737 function (parentObj) {
1738 if (!parentObj.FZero) {
1739 parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1740 parentObj.CPUTicks += 4;
1743 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1748 function (parentObj) {
1749 parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1753 function (parentObj) {
1754 if (!parentObj.FZero) {
1755 var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1756 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1757 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1758 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1759 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1760 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1761 parentObj.programCounter = temp_pc;
1762 parentObj.CPUTicks += 12;
1765 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1770 function (parentObj) {
1771 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1772 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerB);
1773 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1774 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerC);
1778 function (parentObj) {
1779 var dirtySum = parentObj.registerA + parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1780 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
1781 parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
1782 parentObj.FCarry = (dirtySum > 0xFF);
1783 parentObj.registerA = dirtySum & 0xFF;
1784 parentObj.FZero = (parentObj.registerA == 0);
1785 parentObj.FSubtract = false;
1789 function (parentObj) {
1790 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1791 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1792 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1793 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1794 parentObj.programCounter = 0;
1798 function (parentObj) {
1799 if (parentObj.FZero) {
1800 parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1801 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1802 parentObj.CPUTicks += 12;
1807 function (parentObj) {
1808 parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1809 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1813 function (parentObj) {
1814 if (parentObj.FZero) {
1815 parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1816 parentObj.CPUTicks += 4;
1819 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1822 //Secondary OP Code Set:
1824 function (parentObj) {
1825 var opcode = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1826 //Increment the program counter to the next instruction:
1827 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
1828 //Get how many CPU cycles the current 0xCBXX op code counts for:
1829 parentObj.CPUTicks += parentObj.SecondaryTICKTable[opcode];
1830 //Execute secondary OP codes for the 0xCB OP code call.
1831 parentObj.CBOPCODE[opcode](parentObj);
1835 function (parentObj) {
1836 if (parentObj.FZero) {
1837 var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1838 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1839 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1840 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1841 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1842 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1843 parentObj.programCounter = temp_pc;
1844 parentObj.CPUTicks += 12;
1847 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1852 function (parentObj) {
1853 var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1854 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1855 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1856 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1857 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1858 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1859 parentObj.programCounter = temp_pc;
1863 function (parentObj) {
1864 var tempValue = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1865 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
1866 var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
1867 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
1868 parentObj.FCarry = (dirtySum > 0xFF);
1869 parentObj.registerA = dirtySum & 0xFF;
1870 parentObj.FZero = (parentObj.registerA == 0);
1871 parentObj.FSubtract = false;
1875 function (parentObj) {
1876 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1877 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1878 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1879 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1880 parentObj.programCounter = 0x8;
1884 function (parentObj) {
1885 if (!parentObj.FCarry) {
1886 parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1887 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1888 parentObj.CPUTicks += 12;
1893 function (parentObj) {
1894 parentObj.registerE = parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1895 parentObj.registerD = parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF);
1896 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1900 function (parentObj) {
1901 if (!parentObj.FCarry) {
1902 parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1903 parentObj.CPUTicks += 4;
1906 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1911 function (parentObj) {
1912 cout("Illegal op code 0xD3 called, pausing emulation.", 2);
1917 function (parentObj) {
1918 if (!parentObj.FCarry) {
1919 var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1920 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1921 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1922 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1923 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1924 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1925 parentObj.programCounter = temp_pc;
1926 parentObj.CPUTicks += 12;
1929 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1934 function (parentObj) {
1935 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1936 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerD);
1937 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1938 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerE);
1942 function (parentObj) {
1943 var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1944 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
1945 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
1946 parentObj.FCarry = (dirtySum < 0);
1947 parentObj.registerA = dirtySum & 0xFF;
1948 parentObj.FZero = (dirtySum == 0);
1949 parentObj.FSubtract = true;
1953 function (parentObj) {
1954 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1955 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
1956 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
1957 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
1958 parentObj.programCounter = 0x10;
1962 function (parentObj) {
1963 if (parentObj.FCarry) {
1964 parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1965 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1966 parentObj.CPUTicks += 12;
1971 function (parentObj) {
1972 parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
1973 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
1974 //Immediate for HALT:
1975 parentObj.IRQEnableDelay = (parentObj.IRQEnableDelay == 2 || parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) == 0x76) ? 1 : 2;
1979 function (parentObj) {
1980 if (parentObj.FCarry) {
1981 parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1982 parentObj.CPUTicks += 4;
1985 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
1990 function (parentObj) {
1991 cout("Illegal op code 0xDB called, pausing emulation.", 2);
1996 function (parentObj) {
1997 if (parentObj.FCarry) {
1998 var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
1999 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
2000 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2001 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
2002 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2003 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
2004 parentObj.programCounter = temp_pc;
2005 parentObj.CPUTicks += 12;
2008 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
2013 function (parentObj) {
2014 cout("Illegal op code 0xDD called, pausing emulation.", 2);
2019 function (parentObj) {
2020 var temp_var = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
2021 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2022 var dirtySum = parentObj.registerA - temp_var - ((parentObj.FCarry) ? 1 : 0);
2023 parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (temp_var & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
2024 parentObj.FCarry = (dirtySum < 0);
2025 parentObj.registerA = dirtySum & 0xFF;
2026 parentObj.FZero = (parentObj.registerA == 0);
2027 parentObj.FSubtract = true;
2031 function (parentObj) {
2032 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2033 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
2034 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2035 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
2036 parentObj.programCounter = 0x18;
2040 function (parentObj) {
2041 parentObj.memoryHighWrite(parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter), parentObj.registerA);
2042 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2046 function (parentObj) {
2047 parentObj.registersHL = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
2048 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
2050 //LD (0xFF00 + C), A
2052 function (parentObj) {
2053 parentObj.memoryHighWriter[parentObj.registerC](parentObj, parentObj.registerC, parentObj.registerA);
2057 function (parentObj) {
2058 cout("Illegal op code 0xE3 called, pausing emulation.", 2);
2063 function (parentObj) {
2064 cout("Illegal op code 0xE4 called, pausing emulation.", 2);
2069 function (parentObj) {
2070 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2071 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registersHL >> 8);
2072 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2073 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registersHL & 0xFF);
2077 function (parentObj) {
2078 parentObj.registerA &= parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
2079 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2080 parentObj.FZero = (parentObj.registerA == 0);
2081 parentObj.FHalfCarry = true;
2082 parentObj.FSubtract = parentObj.FCarry = false;
2086 function (parentObj) {
2087 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2088 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
2089 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2090 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
2091 parentObj.programCounter = 0x20;
2095 function (parentObj) {
2096 var temp_value2 = (parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24;
2097 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2098 var temp_value = (parentObj.stackPointer + temp_value2) & 0xFFFF;
2099 temp_value2 = parentObj.stackPointer ^ temp_value2 ^ temp_value;
2100 parentObj.stackPointer = temp_value;
2101 parentObj.FCarry = ((temp_value2 & 0x100) == 0x100);
2102 parentObj.FHalfCarry = ((temp_value2 & 0x10) == 0x10);
2103 parentObj.FZero = parentObj.FSubtract = false;
2107 function (parentObj) {
2108 parentObj.programCounter = parentObj.registersHL;
2112 function (parentObj) {
2113 parentObj.memoryWrite((parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter), parentObj.registerA);
2114 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
2118 function (parentObj) {
2119 cout("Illegal op code 0xEB called, pausing emulation.", 2);
2124 function (parentObj) {
2125 cout("Illegal op code 0xEC called, pausing emulation.", 2);
2130 function (parentObj) {
2131 cout("Illegal op code 0xED called, pausing emulation.", 2);
2136 function (parentObj) {
2137 parentObj.registerA ^= parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
2138 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2139 parentObj.FZero = (parentObj.registerA == 0);
2140 parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
2144 function (parentObj) {
2145 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2146 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
2147 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2148 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
2149 parentObj.programCounter = 0x28;
2153 function (parentObj) {
2154 parentObj.registerA = parentObj.memoryHighRead(parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter));
2155 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2159 function (parentObj) {
2160 var temp_var = parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
2161 parentObj.FZero = (temp_var > 0x7F);
2162 parentObj.FSubtract = ((temp_var & 0x40) == 0x40);
2163 parentObj.FHalfCarry = ((temp_var & 0x20) == 0x20);
2164 parentObj.FCarry = ((temp_var & 0x10) == 0x10);
2165 parentObj.registerA = parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF);
2166 parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
2168 //LD A, (0xFF00 + C)
2170 function (parentObj) {
2171 parentObj.registerA = parentObj.memoryHighReader[parentObj.registerC](parentObj, parentObj.registerC);
2175 function (parentObj) {
2176 parentObj.IME = false;
2177 parentObj.IRQEnableDelay = 0;
2181 function (parentObj) {
2182 cout("Illegal op code 0xF4 called, pausing emulation.", 2);
2187 function (parentObj) {
2188 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2189 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerA);
2190 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2191 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, ((parentObj.FZero) ? 0x80 : 0) | ((parentObj.FSubtract) ? 0x40 : 0) | ((parentObj.FHalfCarry) ? 0x20 : 0) | ((parentObj.FCarry) ? 0x10 : 0));
2195 function (parentObj) {
2196 parentObj.registerA |= parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
2197 parentObj.FZero = (parentObj.registerA == 0);
2198 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2199 parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
2203 function (parentObj) {
2204 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2205 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
2206 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2207 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
2208 parentObj.programCounter = 0x30;
2212 function (parentObj) {
2213 var temp_var = (parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24;
2214 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2215 parentObj.registersHL = (parentObj.stackPointer + temp_var) & 0xFFFF;
2216 temp_var = parentObj.stackPointer ^ temp_var ^ parentObj.registersHL;
2217 parentObj.FCarry = ((temp_var & 0x100) == 0x100);
2218 parentObj.FHalfCarry = ((temp_var & 0x10) == 0x10);
2219 parentObj.FZero = parentObj.FSubtract = false;
2223 function (parentObj) {
2224 parentObj.stackPointer = parentObj.registersHL;
2228 function (parentObj) {
2229 parentObj.registerA = parentObj.memoryRead((parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter));
2230 parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
2234 function (parentObj) {
2235 //Immediate for HALT:
2236 parentObj.IRQEnableDelay = (parentObj.IRQEnableDelay == 2 || parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) == 0x76) ? 1 : 2;
2240 function (parentObj) {
2241 cout("Illegal op code 0xFC called, pausing emulation.", 2);
2246 function (parentObj) {
2247 cout("Illegal op code 0xFD called, pausing emulation.", 2);
2252 function (parentObj) {
2253 var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
2254 parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
2255 parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
2256 parentObj.FCarry = (dirtySum < 0);
2257 parentObj.FZero = (dirtySum == 0);
2258 parentObj.FSubtract = true;
2262 function (parentObj) {
2263 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2264 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
2265 parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
2266 parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
2267 parentObj.programCounter = 0x38;
2270 GameBoyCore.prototype.CBOPCODE = [
2273 function (parentObj) {
2274 parentObj.FCarry = (parentObj.registerB > 0x7F);
2275 parentObj.registerB = ((parentObj.registerB << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2276 parentObj.FHalfCarry = parentObj.FSubtract = false;
2277 parentObj.FZero = (parentObj.registerB == 0);
2281 ,function (parentObj) {
2282 parentObj.FCarry = (parentObj.registerC > 0x7F);
2283 parentObj.registerC = ((parentObj.registerC << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2284 parentObj.FHalfCarry = parentObj.FSubtract = false;
2285 parentObj.FZero = (parentObj.registerC == 0);
2289 ,function (parentObj) {
2290 parentObj.FCarry = (parentObj.registerD > 0x7F);
2291 parentObj.registerD = ((parentObj.registerD << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2292 parentObj.FHalfCarry = parentObj.FSubtract = false;
2293 parentObj.FZero = (parentObj.registerD == 0);
2297 ,function (parentObj) {
2298 parentObj.FCarry = (parentObj.registerE > 0x7F);
2299 parentObj.registerE = ((parentObj.registerE << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2300 parentObj.FHalfCarry = parentObj.FSubtract = false;
2301 parentObj.FZero = (parentObj.registerE == 0);
2305 ,function (parentObj) {
2306 parentObj.FCarry = (parentObj.registersHL > 0x7FFF);
2307 parentObj.registersHL = ((parentObj.registersHL << 1) & 0xFE00) | ((parentObj.FCarry) ? 0x100 : 0) | (parentObj.registersHL & 0xFF);
2308 parentObj.FHalfCarry = parentObj.FSubtract = false;
2309 parentObj.FZero = (parentObj.registersHL < 0x100);
2313 ,function (parentObj) {
2314 parentObj.FCarry = ((parentObj.registersHL & 0x80) == 0x80);
2315 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2316 parentObj.FHalfCarry = parentObj.FSubtract = false;
2317 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2321 ,function (parentObj) {
2322 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2323 parentObj.FCarry = (temp_var > 0x7F);
2324 temp_var = ((temp_var << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2325 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2326 parentObj.FHalfCarry = parentObj.FSubtract = false;
2327 parentObj.FZero = (temp_var == 0);
2331 ,function (parentObj) {
2332 parentObj.FCarry = (parentObj.registerA > 0x7F);
2333 parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2334 parentObj.FHalfCarry = parentObj.FSubtract = false;
2335 parentObj.FZero = (parentObj.registerA == 0);
2339 ,function (parentObj) {
2340 parentObj.FCarry = ((parentObj.registerB & 0x01) == 0x01);
2341 parentObj.registerB = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerB >> 1);
2342 parentObj.FHalfCarry = parentObj.FSubtract = false;
2343 parentObj.FZero = (parentObj.registerB == 0);
2347 ,function (parentObj) {
2348 parentObj.FCarry = ((parentObj.registerC & 0x01) == 0x01);
2349 parentObj.registerC = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerC >> 1);
2350 parentObj.FHalfCarry = parentObj.FSubtract = false;
2351 parentObj.FZero = (parentObj.registerC == 0);
2355 ,function (parentObj) {
2356 parentObj.FCarry = ((parentObj.registerD & 0x01) == 0x01);
2357 parentObj.registerD = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerD >> 1);
2358 parentObj.FHalfCarry = parentObj.FSubtract = false;
2359 parentObj.FZero = (parentObj.registerD == 0);
2363 ,function (parentObj) {
2364 parentObj.FCarry = ((parentObj.registerE & 0x01) == 0x01);
2365 parentObj.registerE = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerE >> 1);
2366 parentObj.FHalfCarry = parentObj.FSubtract = false;
2367 parentObj.FZero = (parentObj.registerE == 0);
2371 ,function (parentObj) {
2372 parentObj.FCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
2373 parentObj.registersHL = ((parentObj.FCarry) ? 0x8000 : 0) | ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0xFF);
2374 parentObj.FHalfCarry = parentObj.FSubtract = false;
2375 parentObj.FZero = (parentObj.registersHL < 0x100);
2379 ,function (parentObj) {
2380 parentObj.FCarry = ((parentObj.registersHL & 0x01) == 0x01);
2381 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.FCarry) ? 0x80 : 0) | ((parentObj.registersHL & 0xFF) >> 1);
2382 parentObj.FHalfCarry = parentObj.FSubtract = false;
2383 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2387 ,function (parentObj) {
2388 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2389 parentObj.FCarry = ((temp_var & 0x01) == 0x01);
2390 temp_var = ((parentObj.FCarry) ? 0x80 : 0) | (temp_var >> 1);
2391 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2392 parentObj.FHalfCarry = parentObj.FSubtract = false;
2393 parentObj.FZero = (temp_var == 0);
2397 ,function (parentObj) {
2398 parentObj.FCarry = ((parentObj.registerA & 0x01) == 0x01);
2399 parentObj.registerA = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerA >> 1);
2400 parentObj.FHalfCarry = parentObj.FSubtract = false;
2401 parentObj.FZero = (parentObj.registerA == 0);
2405 ,function (parentObj) {
2406 var newFCarry = (parentObj.registerB > 0x7F);
2407 parentObj.registerB = ((parentObj.registerB << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2408 parentObj.FCarry = newFCarry;
2409 parentObj.FHalfCarry = parentObj.FSubtract = false;
2410 parentObj.FZero = (parentObj.registerB == 0);
2414 ,function (parentObj) {
2415 var newFCarry = (parentObj.registerC > 0x7F);
2416 parentObj.registerC = ((parentObj.registerC << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2417 parentObj.FCarry = newFCarry;
2418 parentObj.FHalfCarry = parentObj.FSubtract = false;
2419 parentObj.FZero = (parentObj.registerC == 0);
2423 ,function (parentObj) {
2424 var newFCarry = (parentObj.registerD > 0x7F);
2425 parentObj.registerD = ((parentObj.registerD << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2426 parentObj.FCarry = newFCarry;
2427 parentObj.FHalfCarry = parentObj.FSubtract = false;
2428 parentObj.FZero = (parentObj.registerD == 0);
2432 ,function (parentObj) {
2433 var newFCarry = (parentObj.registerE > 0x7F);
2434 parentObj.registerE = ((parentObj.registerE << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2435 parentObj.FCarry = newFCarry;
2436 parentObj.FHalfCarry = parentObj.FSubtract = false;
2437 parentObj.FZero = (parentObj.registerE == 0);
2441 ,function (parentObj) {
2442 var newFCarry = (parentObj.registersHL > 0x7FFF);
2443 parentObj.registersHL = ((parentObj.registersHL << 1) & 0xFE00) | ((parentObj.FCarry) ? 0x100 : 0) | (parentObj.registersHL & 0xFF);
2444 parentObj.FCarry = newFCarry;
2445 parentObj.FHalfCarry = parentObj.FSubtract = false;
2446 parentObj.FZero = (parentObj.registersHL < 0x100);
2450 ,function (parentObj) {
2451 var newFCarry = ((parentObj.registersHL & 0x80) == 0x80);
2452 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2453 parentObj.FCarry = newFCarry;
2454 parentObj.FHalfCarry = parentObj.FSubtract = false;
2455 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2459 ,function (parentObj) {
2460 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2461 var newFCarry = (temp_var > 0x7F);
2462 temp_var = ((temp_var << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2463 parentObj.FCarry = newFCarry;
2464 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2465 parentObj.FHalfCarry = parentObj.FSubtract = false;
2466 parentObj.FZero = (temp_var == 0);
2470 ,function (parentObj) {
2471 var newFCarry = (parentObj.registerA > 0x7F);
2472 parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
2473 parentObj.FCarry = newFCarry;
2474 parentObj.FHalfCarry = parentObj.FSubtract = false;
2475 parentObj.FZero = (parentObj.registerA == 0);
2479 ,function (parentObj) {
2480 var newFCarry = ((parentObj.registerB & 0x01) == 0x01);
2481 parentObj.registerB = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerB >> 1);
2482 parentObj.FCarry = newFCarry;
2483 parentObj.FHalfCarry = parentObj.FSubtract = false;
2484 parentObj.FZero = (parentObj.registerB == 0);
2488 ,function (parentObj) {
2489 var newFCarry = ((parentObj.registerC & 0x01) == 0x01);
2490 parentObj.registerC = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerC >> 1);
2491 parentObj.FCarry = newFCarry;
2492 parentObj.FHalfCarry = parentObj.FSubtract = false;
2493 parentObj.FZero = (parentObj.registerC == 0);
2497 ,function (parentObj) {
2498 var newFCarry = ((parentObj.registerD & 0x01) == 0x01);
2499 parentObj.registerD = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerD >> 1);
2500 parentObj.FCarry = newFCarry;
2501 parentObj.FHalfCarry = parentObj.FSubtract = false;
2502 parentObj.FZero = (parentObj.registerD == 0);
2506 ,function (parentObj) {
2507 var newFCarry = ((parentObj.registerE & 0x01) == 0x01);
2508 parentObj.registerE = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerE >> 1);
2509 parentObj.FCarry = newFCarry;
2510 parentObj.FHalfCarry = parentObj.FSubtract = false;
2511 parentObj.FZero = (parentObj.registerE == 0);
2515 ,function (parentObj) {
2516 var newFCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
2517 parentObj.registersHL = ((parentObj.FCarry) ? 0x8000 : 0) | ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0xFF);
2518 parentObj.FCarry = newFCarry;
2519 parentObj.FHalfCarry = parentObj.FSubtract = false;
2520 parentObj.FZero = (parentObj.registersHL < 0x100);
2524 ,function (parentObj) {
2525 var newFCarry = ((parentObj.registersHL & 0x01) == 0x01);
2526 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.FCarry) ? 0x80 : 0) | ((parentObj.registersHL & 0xFF) >> 1);
2527 parentObj.FCarry = newFCarry;
2528 parentObj.FHalfCarry = parentObj.FSubtract = false;
2529 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2533 ,function (parentObj) {
2534 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2535 var newFCarry = ((temp_var & 0x01) == 0x01);
2536 temp_var = ((parentObj.FCarry) ? 0x80 : 0) | (temp_var >> 1);
2537 parentObj.FCarry = newFCarry;
2538 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2539 parentObj.FHalfCarry = parentObj.FSubtract = false;
2540 parentObj.FZero = (temp_var == 0);
2544 ,function (parentObj) {
2545 var newFCarry = ((parentObj.registerA & 0x01) == 0x01);
2546 parentObj.registerA = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerA >> 1);
2547 parentObj.FCarry = newFCarry;
2548 parentObj.FHalfCarry = parentObj.FSubtract = false;
2549 parentObj.FZero = (parentObj.registerA == 0);
2553 ,function (parentObj) {
2554 parentObj.FCarry = (parentObj.registerB > 0x7F);
2555 parentObj.registerB = (parentObj.registerB << 1) & 0xFF;
2556 parentObj.FHalfCarry = parentObj.FSubtract = false;
2557 parentObj.FZero = (parentObj.registerB == 0);
2561 ,function (parentObj) {
2562 parentObj.FCarry = (parentObj.registerC > 0x7F);
2563 parentObj.registerC = (parentObj.registerC << 1) & 0xFF;
2564 parentObj.FHalfCarry = parentObj.FSubtract = false;
2565 parentObj.FZero = (parentObj.registerC == 0);
2569 ,function (parentObj) {
2570 parentObj.FCarry = (parentObj.registerD > 0x7F);
2571 parentObj.registerD = (parentObj.registerD << 1) & 0xFF;
2572 parentObj.FHalfCarry = parentObj.FSubtract = false;
2573 parentObj.FZero = (parentObj.registerD == 0);
2577 ,function (parentObj) {
2578 parentObj.FCarry = (parentObj.registerE > 0x7F);
2579 parentObj.registerE = (parentObj.registerE << 1) & 0xFF;
2580 parentObj.FHalfCarry = parentObj.FSubtract = false;
2581 parentObj.FZero = (parentObj.registerE == 0);
2585 ,function (parentObj) {
2586 parentObj.FCarry = (parentObj.registersHL > 0x7FFF);
2587 parentObj.registersHL = ((parentObj.registersHL << 1) & 0xFE00) | (parentObj.registersHL & 0xFF);
2588 parentObj.FHalfCarry = parentObj.FSubtract = false;
2589 parentObj.FZero = (parentObj.registersHL < 0x100);
2593 ,function (parentObj) {
2594 parentObj.FCarry = ((parentObj.registersHL & 0x0080) == 0x0080);
2595 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL << 1) & 0xFF);
2596 parentObj.FHalfCarry = parentObj.FSubtract = false;
2597 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2601 ,function (parentObj) {
2602 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2603 parentObj.FCarry = (temp_var > 0x7F);
2604 temp_var = (temp_var << 1) & 0xFF;
2605 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2606 parentObj.FHalfCarry = parentObj.FSubtract = false;
2607 parentObj.FZero = (temp_var == 0);
2611 ,function (parentObj) {
2612 parentObj.FCarry = (parentObj.registerA > 0x7F);
2613 parentObj.registerA = (parentObj.registerA << 1) & 0xFF;
2614 parentObj.FHalfCarry = parentObj.FSubtract = false;
2615 parentObj.FZero = (parentObj.registerA == 0);
2619 ,function (parentObj) {
2620 parentObj.FCarry = ((parentObj.registerB & 0x01) == 0x01);
2621 parentObj.registerB = (parentObj.registerB & 0x80) | (parentObj.registerB >> 1);
2622 parentObj.FHalfCarry = parentObj.FSubtract = false;
2623 parentObj.FZero = (parentObj.registerB == 0);
2627 ,function (parentObj) {
2628 parentObj.FCarry = ((parentObj.registerC & 0x01) == 0x01);
2629 parentObj.registerC = (parentObj.registerC & 0x80) | (parentObj.registerC >> 1);
2630 parentObj.FHalfCarry = parentObj.FSubtract = false;
2631 parentObj.FZero = (parentObj.registerC == 0);
2635 ,function (parentObj) {
2636 parentObj.FCarry = ((parentObj.registerD & 0x01) == 0x01);
2637 parentObj.registerD = (parentObj.registerD & 0x80) | (parentObj.registerD >> 1);
2638 parentObj.FHalfCarry = parentObj.FSubtract = false;
2639 parentObj.FZero = (parentObj.registerD == 0);
2643 ,function (parentObj) {
2644 parentObj.FCarry = ((parentObj.registerE & 0x01) == 0x01);
2645 parentObj.registerE = (parentObj.registerE & 0x80) | (parentObj.registerE >> 1);
2646 parentObj.FHalfCarry = parentObj.FSubtract = false;
2647 parentObj.FZero = (parentObj.registerE == 0);
2651 ,function (parentObj) {
2652 parentObj.FCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
2653 parentObj.registersHL = ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0x80FF);
2654 parentObj.FHalfCarry = parentObj.FSubtract = false;
2655 parentObj.FZero = (parentObj.registersHL < 0x100);
2659 ,function (parentObj) {
2660 parentObj.FCarry = ((parentObj.registersHL & 0x0001) == 0x0001);
2661 parentObj.registersHL = (parentObj.registersHL & 0xFF80) | ((parentObj.registersHL & 0xFF) >> 1);
2662 parentObj.FHalfCarry = parentObj.FSubtract = false;
2663 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2667 ,function (parentObj) {
2668 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2669 parentObj.FCarry = ((temp_var & 0x01) == 0x01);
2670 temp_var = (temp_var & 0x80) | (temp_var >> 1);
2671 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2672 parentObj.FHalfCarry = parentObj.FSubtract = false;
2673 parentObj.FZero = (temp_var == 0);
2677 ,function (parentObj) {
2678 parentObj.FCarry = ((parentObj.registerA & 0x01) == 0x01);
2679 parentObj.registerA = (parentObj.registerA & 0x80) | (parentObj.registerA >> 1);
2680 parentObj.FHalfCarry = parentObj.FSubtract = false;
2681 parentObj.FZero = (parentObj.registerA == 0);
2685 ,function (parentObj) {
2686 parentObj.registerB = ((parentObj.registerB & 0xF) << 4) | (parentObj.registerB >> 4);
2687 parentObj.FZero = (parentObj.registerB == 0);
2688 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2692 ,function (parentObj) {
2693 parentObj.registerC = ((parentObj.registerC & 0xF) << 4) | (parentObj.registerC >> 4);
2694 parentObj.FZero = (parentObj.registerC == 0);
2695 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2699 ,function (parentObj) {
2700 parentObj.registerD = ((parentObj.registerD & 0xF) << 4) | (parentObj.registerD >> 4);
2701 parentObj.FZero = (parentObj.registerD == 0);
2702 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2706 ,function (parentObj) {
2707 parentObj.registerE = ((parentObj.registerE & 0xF) << 4) | (parentObj.registerE >> 4);
2708 parentObj.FZero = (parentObj.registerE == 0);
2709 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2713 ,function (parentObj) {
2714 parentObj.registersHL = ((parentObj.registersHL & 0xF00) << 4) | ((parentObj.registersHL & 0xF000) >> 4) | (parentObj.registersHL & 0xFF);
2715 parentObj.FZero = (parentObj.registersHL < 0x100);
2716 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2720 ,function (parentObj) {
2721 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL & 0xF) << 4) | ((parentObj.registersHL & 0xF0) >> 4);
2722 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2723 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2727 ,function (parentObj) {
2728 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2729 temp_var = ((temp_var & 0xF) << 4) | (temp_var >> 4);
2730 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
2731 parentObj.FZero = (temp_var == 0);
2732 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2736 ,function (parentObj) {
2737 parentObj.registerA = ((parentObj.registerA & 0xF) << 4) | (parentObj.registerA >> 4);
2738 parentObj.FZero = (parentObj.registerA == 0);
2739 parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
2743 ,function (parentObj) {
2744 parentObj.FCarry = ((parentObj.registerB & 0x01) == 0x01);
2745 parentObj.registerB >>= 1;
2746 parentObj.FHalfCarry = parentObj.FSubtract = false;
2747 parentObj.FZero = (parentObj.registerB == 0);
2751 ,function (parentObj) {
2752 parentObj.FCarry = ((parentObj.registerC & 0x01) == 0x01);
2753 parentObj.registerC >>= 1;
2754 parentObj.FHalfCarry = parentObj.FSubtract = false;
2755 parentObj.FZero = (parentObj.registerC == 0);
2759 ,function (parentObj) {
2760 parentObj.FCarry = ((parentObj.registerD & 0x01) == 0x01);
2761 parentObj.registerD >>= 1;
2762 parentObj.FHalfCarry = parentObj.FSubtract = false;
2763 parentObj.FZero = (parentObj.registerD == 0);
2767 ,function (parentObj) {
2768 parentObj.FCarry = ((parentObj.registerE & 0x01) == 0x01);
2769 parentObj.registerE >>= 1;
2770 parentObj.FHalfCarry = parentObj.FSubtract = false;
2771 parentObj.FZero = (parentObj.registerE == 0);
2775 ,function (parentObj) {
2776 parentObj.FCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
2777 parentObj.registersHL = ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0xFF);
2778 parentObj.FHalfCarry = parentObj.FSubtract = false;
2779 parentObj.FZero = (parentObj.registersHL < 0x100);
2783 ,function (parentObj) {
2784 parentObj.FCarry = ((parentObj.registersHL & 0x0001) == 0x0001);
2785 parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL & 0xFF) >> 1);
2786 parentObj.FHalfCarry = parentObj.FSubtract = false;
2787 parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
2791 ,function (parentObj) {
2792 var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
2793 parentObj.FCarry = ((temp_var & 0x01) == 0x01);
2794 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var >> 1);
2795 parentObj.FHalfCarry = parentObj.FSubtract = false;
2796 parentObj.FZero = (temp_var < 2);
2800 ,function (parentObj) {
2801 parentObj.FCarry = ((parentObj.registerA & 0x01) == 0x01);
2802 parentObj.registerA >>= 1;
2803 parentObj.FHalfCarry = parentObj.FSubtract = false;
2804 parentObj.FZero = (parentObj.registerA == 0);
2808 ,function (parentObj) {
2809 parentObj.FHalfCarry = true;
2810 parentObj.FSubtract = false;
2811 parentObj.FZero = ((parentObj.registerB & 0x01) == 0);
2815 ,function (parentObj) {
2816 parentObj.FHalfCarry = true;
2817 parentObj.FSubtract = false;
2818 parentObj.FZero = ((parentObj.registerC & 0x01) == 0);
2822 ,function (parentObj) {
2823 parentObj.FHalfCarry = true;
2824 parentObj.FSubtract = false;
2825 parentObj.FZero = ((parentObj.registerD & 0x01) == 0);
2829 ,function (parentObj) {
2830 parentObj.FHalfCarry = true;
2831 parentObj.FSubtract = false;
2832 parentObj.FZero = ((parentObj.registerE & 0x01) == 0);
2836 ,function (parentObj) {
2837 parentObj.FHalfCarry = true;
2838 parentObj.FSubtract = false;
2839 parentObj.FZero = ((parentObj.registersHL & 0x0100) == 0);
2843 ,function (parentObj) {
2844 parentObj.FHalfCarry = true;
2845 parentObj.FSubtract = false;
2846 parentObj.FZero = ((parentObj.registersHL & 0x0001) == 0);
2850 ,function (parentObj) {
2851 parentObj.FHalfCarry = true;
2852 parentObj.FSubtract = false;
2853 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x01) == 0);
2857 ,function (parentObj) {
2858 parentObj.FHalfCarry = true;
2859 parentObj.FSubtract = false;
2860 parentObj.FZero = ((parentObj.registerA & 0x01) == 0);
2864 ,function (parentObj) {
2865 parentObj.FHalfCarry = true;
2866 parentObj.FSubtract = false;
2867 parentObj.FZero = ((parentObj.registerB & 0x02) == 0);
2871 ,function (parentObj) {
2872 parentObj.FHalfCarry = true;
2873 parentObj.FSubtract = false;
2874 parentObj.FZero = ((parentObj.registerC & 0x02) == 0);
2878 ,function (parentObj) {
2879 parentObj.FHalfCarry = true;
2880 parentObj.FSubtract = false;
2881 parentObj.FZero = ((parentObj.registerD & 0x02) == 0);
2885 ,function (parentObj) {
2886 parentObj.FHalfCarry = true;
2887 parentObj.FSubtract = false;
2888 parentObj.FZero = ((parentObj.registerE & 0x02) == 0);
2892 ,function (parentObj) {
2893 parentObj.FHalfCarry = true;
2894 parentObj.FSubtract = false;
2895 parentObj.FZero = ((parentObj.registersHL & 0x0200) == 0);
2899 ,function (parentObj) {
2900 parentObj.FHalfCarry = true;
2901 parentObj.FSubtract = false;
2902 parentObj.FZero = ((parentObj.registersHL & 0x0002) == 0);
2906 ,function (parentObj) {
2907 parentObj.FHalfCarry = true;
2908 parentObj.FSubtract = false;
2909 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x02) == 0);
2913 ,function (parentObj) {
2914 parentObj.FHalfCarry = true;
2915 parentObj.FSubtract = false;
2916 parentObj.FZero = ((parentObj.registerA & 0x02) == 0);
2920 ,function (parentObj) {
2921 parentObj.FHalfCarry = true;
2922 parentObj.FSubtract = false;
2923 parentObj.FZero = ((parentObj.registerB & 0x04) == 0);
2927 ,function (parentObj) {
2928 parentObj.FHalfCarry = true;
2929 parentObj.FSubtract = false;
2930 parentObj.FZero = ((parentObj.registerC & 0x04) == 0);
2934 ,function (parentObj) {
2935 parentObj.FHalfCarry = true;
2936 parentObj.FSubtract = false;
2937 parentObj.FZero = ((parentObj.registerD & 0x04) == 0);
2941 ,function (parentObj) {
2942 parentObj.FHalfCarry = true;
2943 parentObj.FSubtract = false;
2944 parentObj.FZero = ((parentObj.registerE & 0x04) == 0);
2948 ,function (parentObj) {
2949 parentObj.FHalfCarry = true;
2950 parentObj.FSubtract = false;
2951 parentObj.FZero = ((parentObj.registersHL & 0x0400) == 0);
2955 ,function (parentObj) {
2956 parentObj.FHalfCarry = true;
2957 parentObj.FSubtract = false;
2958 parentObj.FZero = ((parentObj.registersHL & 0x0004) == 0);
2962 ,function (parentObj) {
2963 parentObj.FHalfCarry = true;
2964 parentObj.FSubtract = false;
2965 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x04) == 0);
2969 ,function (parentObj) {
2970 parentObj.FHalfCarry = true;
2971 parentObj.FSubtract = false;
2972 parentObj.FZero = ((parentObj.registerA & 0x04) == 0);
2976 ,function (parentObj) {
2977 parentObj.FHalfCarry = true;
2978 parentObj.FSubtract = false;
2979 parentObj.FZero = ((parentObj.registerB & 0x08) == 0);
2983 ,function (parentObj) {
2984 parentObj.FHalfCarry = true;
2985 parentObj.FSubtract = false;
2986 parentObj.FZero = ((parentObj.registerC & 0x08) == 0);
2990 ,function (parentObj) {
2991 parentObj.FHalfCarry = true;
2992 parentObj.FSubtract = false;
2993 parentObj.FZero = ((parentObj.registerD & 0x08) == 0);
2997 ,function (parentObj) {
2998 parentObj.FHalfCarry = true;
2999 parentObj.FSubtract = false;
3000 parentObj.FZero = ((parentObj.registerE & 0x08) == 0);
3004 ,function (parentObj) {
3005 parentObj.FHalfCarry = true;
3006 parentObj.FSubtract = false;
3007 parentObj.FZero = ((parentObj.registersHL & 0x0800) == 0);
3011 ,function (parentObj) {
3012 parentObj.FHalfCarry = true;
3013 parentObj.FSubtract = false;
3014 parentObj.FZero = ((parentObj.registersHL & 0x0008) == 0);
3018 ,function (parentObj) {
3019 parentObj.FHalfCarry = true;
3020 parentObj.FSubtract = false;
3021 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x08) == 0);
3025 ,function (parentObj) {
3026 parentObj.FHalfCarry = true;
3027 parentObj.FSubtract = false;
3028 parentObj.FZero = ((parentObj.registerA & 0x08) == 0);
3032 ,function (parentObj) {
3033 parentObj.FHalfCarry = true;
3034 parentObj.FSubtract = false;
3035 parentObj.FZero = ((parentObj.registerB & 0x10) == 0);
3039 ,function (parentObj) {
3040 parentObj.FHalfCarry = true;
3041 parentObj.FSubtract = false;
3042 parentObj.FZero = ((parentObj.registerC & 0x10) == 0);
3046 ,function (parentObj) {
3047 parentObj.FHalfCarry = true;
3048 parentObj.FSubtract = false;
3049 parentObj.FZero = ((parentObj.registerD & 0x10) == 0);
3053 ,function (parentObj) {
3054 parentObj.FHalfCarry = true;
3055 parentObj.FSubtract = false;
3056 parentObj.FZero = ((parentObj.registerE & 0x10) == 0);
3060 ,function (parentObj) {
3061 parentObj.FHalfCarry = true;
3062 parentObj.FSubtract = false;
3063 parentObj.FZero = ((parentObj.registersHL & 0x1000) == 0);
3067 ,function (parentObj) {
3068 parentObj.FHalfCarry = true;
3069 parentObj.FSubtract = false;
3070 parentObj.FZero = ((parentObj.registersHL & 0x0010) == 0);
3074 ,function (parentObj) {
3075 parentObj.FHalfCarry = true;
3076 parentObj.FSubtract = false;
3077 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x10) == 0);
3081 ,function (parentObj) {
3082 parentObj.FHalfCarry = true;
3083 parentObj.FSubtract = false;
3084 parentObj.FZero = ((parentObj.registerA & 0x10) == 0);
3088 ,function (parentObj) {
3089 parentObj.FHalfCarry = true;
3090 parentObj.FSubtract = false;
3091 parentObj.FZero = ((parentObj.registerB & 0x20) == 0);
3095 ,function (parentObj) {
3096 parentObj.FHalfCarry = true;
3097 parentObj.FSubtract = false;
3098 parentObj.FZero = ((parentObj.registerC & 0x20) == 0);
3102 ,function (parentObj) {
3103 parentObj.FHalfCarry = true;
3104 parentObj.FSubtract = false;
3105 parentObj.FZero = ((parentObj.registerD & 0x20) == 0);
3109 ,function (parentObj) {
3110 parentObj.FHalfCarry = true;
3111 parentObj.FSubtract = false;
3112 parentObj.FZero = ((parentObj.registerE & 0x20) == 0);
3116 ,function (parentObj) {
3117 parentObj.FHalfCarry = true;
3118 parentObj.FSubtract = false;
3119 parentObj.FZero = ((parentObj.registersHL & 0x2000) == 0);
3123 ,function (parentObj) {
3124 parentObj.FHalfCarry = true;
3125 parentObj.FSubtract = false;
3126 parentObj.FZero = ((parentObj.registersHL & 0x0020) == 0);
3130 ,function (parentObj) {
3131 parentObj.FHalfCarry = true;
3132 parentObj.FSubtract = false;
3133 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x20) == 0);
3137 ,function (parentObj) {
3138 parentObj.FHalfCarry = true;
3139 parentObj.FSubtract = false;
3140 parentObj.FZero = ((parentObj.registerA & 0x20) == 0);
3144 ,function (parentObj) {
3145 parentObj.FHalfCarry = true;
3146 parentObj.FSubtract = false;
3147 parentObj.FZero = ((parentObj.registerB & 0x40) == 0);
3151 ,function (parentObj) {
3152 parentObj.FHalfCarry = true;
3153 parentObj.FSubtract = false;
3154 parentObj.FZero = ((parentObj.registerC & 0x40) == 0);
3158 ,function (parentObj) {
3159 parentObj.FHalfCarry = true;
3160 parentObj.FSubtract = false;
3161 parentObj.FZero = ((parentObj.registerD & 0x40) == 0);
3165 ,function (parentObj) {
3166 parentObj.FHalfCarry = true;
3167 parentObj.FSubtract = false;
3168 parentObj.FZero = ((parentObj.registerE & 0x40) == 0);
3172 ,function (parentObj) {
3173 parentObj.FHalfCarry = true;
3174 parentObj.FSubtract = false;
3175 parentObj.FZero = ((parentObj.registersHL & 0x4000) == 0);
3179 ,function (parentObj) {
3180 parentObj.FHalfCarry = true;
3181 parentObj.FSubtract = false;
3182 parentObj.FZero = ((parentObj.registersHL & 0x0040) == 0);
3186 ,function (parentObj) {
3187 parentObj.FHalfCarry = true;
3188 parentObj.FSubtract = false;
3189 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x40) == 0);
3193 ,function (parentObj) {
3194 parentObj.FHalfCarry = true;
3195 parentObj.FSubtract = false;
3196 parentObj.FZero = ((parentObj.registerA & 0x40) == 0);
3200 ,function (parentObj) {
3201 parentObj.FHalfCarry = true;
3202 parentObj.FSubtract = false;
3203 parentObj.FZero = ((parentObj.registerB & 0x80) == 0);
3207 ,function (parentObj) {
3208 parentObj.FHalfCarry = true;
3209 parentObj.FSubtract = false;
3210 parentObj.FZero = ((parentObj.registerC & 0x80) == 0);
3214 ,function (parentObj) {
3215 parentObj.FHalfCarry = true;
3216 parentObj.FSubtract = false;
3217 parentObj.FZero = ((parentObj.registerD & 0x80) == 0);
3221 ,function (parentObj) {
3222 parentObj.FHalfCarry = true;
3223 parentObj.FSubtract = false;
3224 parentObj.FZero = ((parentObj.registerE & 0x80) == 0);
3228 ,function (parentObj) {
3229 parentObj.FHalfCarry = true;
3230 parentObj.FSubtract = false;
3231 parentObj.FZero = ((parentObj.registersHL & 0x8000) == 0);
3235 ,function (parentObj) {
3236 parentObj.FHalfCarry = true;
3237 parentObj.FSubtract = false;
3238 parentObj.FZero = ((parentObj.registersHL & 0x0080) == 0);
3242 ,function (parentObj) {
3243 parentObj.FHalfCarry = true;
3244 parentObj.FSubtract = false;
3245 parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x80) == 0);
3249 ,function (parentObj) {
3250 parentObj.FHalfCarry = true;
3251 parentObj.FSubtract = false;
3252 parentObj.FZero = ((parentObj.registerA & 0x80) == 0);
3256 ,function (parentObj) {
3257 parentObj.registerB &= 0xFE;
3261 ,function (parentObj) {
3262 parentObj.registerC &= 0xFE;
3266 ,function (parentObj) {
3267 parentObj.registerD &= 0xFE;
3271 ,function (parentObj) {
3272 parentObj.registerE &= 0xFE;
3276 ,function (parentObj) {
3277 parentObj.registersHL &= 0xFEFF;
3281 ,function (parentObj) {
3282 parentObj.registersHL &= 0xFFFE;
3286 ,function (parentObj) {
3287 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xFE);
3291 ,function (parentObj) {
3292 parentObj.registerA &= 0xFE;
3296 ,function (parentObj) {
3297 parentObj.registerB &= 0xFD;
3301 ,function (parentObj) {
3302 parentObj.registerC &= 0xFD;
3306 ,function (parentObj) {
3307 parentObj.registerD &= 0xFD;
3311 ,function (parentObj) {
3312 parentObj.registerE &= 0xFD;
3316 ,function (parentObj) {
3317 parentObj.registersHL &= 0xFDFF;
3321 ,function (parentObj) {
3322 parentObj.registersHL &= 0xFFFD;
3326 ,function (parentObj) {
3327 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xFD);
3331 ,function (parentObj) {
3332 parentObj.registerA &= 0xFD;
3336 ,function (parentObj) {
3337 parentObj.registerB &= 0xFB;
3341 ,function (parentObj) {
3342 parentObj.registerC &= 0xFB;
3346 ,function (parentObj) {
3347 parentObj.registerD &= 0xFB;
3351 ,function (parentObj) {
3352 parentObj.registerE &= 0xFB;
3356 ,function (parentObj) {
3357 parentObj.registersHL &= 0xFBFF;
3361 ,function (parentObj) {
3362 parentObj.registersHL &= 0xFFFB;
3366 ,function (parentObj) {
3367 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xFB);
3371 ,function (parentObj) {
3372 parentObj.registerA &= 0xFB;
3376 ,function (parentObj) {
3377 parentObj.registerB &= 0xF7;
3381 ,function (parentObj) {
3382 parentObj.registerC &= 0xF7;
3386 ,function (parentObj) {
3387 parentObj.registerD &= 0xF7;
3391 ,function (parentObj) {
3392 parentObj.registerE &= 0xF7;
3396 ,function (parentObj) {
3397 parentObj.registersHL &= 0xF7FF;
3401 ,function (parentObj) {
3402 parentObj.registersHL &= 0xFFF7;
3406 ,function (parentObj) {
3407 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xF7);
3411 ,function (parentObj) {
3412 parentObj.registerA &= 0xF7;
3416 ,function (parentObj) {
3417 parentObj.registerB &= 0xEF;
3421 ,function (parentObj) {
3422 parentObj.registerC &= 0xEF;
3426 ,function (parentObj) {
3427 parentObj.registerD &= 0xEF;
3431 ,function (parentObj) {
3432 parentObj.registerE &= 0xEF;
3436 ,function (parentObj) {
3437 parentObj.registersHL &= 0xEFFF;
3441 ,function (parentObj) {
3442 parentObj.registersHL &= 0xFFEF;
3446 ,function (parentObj) {
3447 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xEF);
3451 ,function (parentObj) {
3452 parentObj.registerA &= 0xEF;
3456 ,function (parentObj) {
3457 parentObj.registerB &= 0xDF;
3461 ,function (parentObj) {
3462 parentObj.registerC &= 0xDF;
3466 ,function (parentObj) {
3467 parentObj.registerD &= 0xDF;
3471 ,function (parentObj) {
3472 parentObj.registerE &= 0xDF;
3476 ,function (parentObj) {
3477 parentObj.registersHL &= 0xDFFF;
3481 ,function (parentObj) {
3482 parentObj.registersHL &= 0xFFDF;
3486 ,function (parentObj) {
3487 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xDF);
3491 ,function (parentObj) {
3492 parentObj.registerA &= 0xDF;
3496 ,function (parentObj) {
3497 parentObj.registerB &= 0xBF;
3501 ,function (parentObj) {
3502 parentObj.registerC &= 0xBF;
3506 ,function (parentObj) {
3507 parentObj.registerD &= 0xBF;
3511 ,function (parentObj) {
3512 parentObj.registerE &= 0xBF;
3516 ,function (parentObj) {
3517 parentObj.registersHL &= 0xBFFF;
3521 ,function (parentObj) {
3522 parentObj.registersHL &= 0xFFBF;
3526 ,function (parentObj) {
3527 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xBF);
3531 ,function (parentObj) {
3532 parentObj.registerA &= 0xBF;
3536 ,function (parentObj) {
3537 parentObj.registerB &= 0x7F;
3541 ,function (parentObj) {
3542 parentObj.registerC &= 0x7F;
3546 ,function (parentObj) {
3547 parentObj.registerD &= 0x7F;
3551 ,function (parentObj) {
3552 parentObj.registerE &= 0x7F;
3556 ,function (parentObj) {
3557 parentObj.registersHL &= 0x7FFF;
3561 ,function (parentObj) {
3562 parentObj.registersHL &= 0xFF7F;
3566 ,function (parentObj) {
3567 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x7F);
3571 ,function (parentObj) {
3572 parentObj.registerA &= 0x7F;
3576 ,function (parentObj) {
3577 parentObj.registerB |= 0x01;
3581 ,function (parentObj) {
3582 parentObj.registerC |= 0x01;
3586 ,function (parentObj) {
3587 parentObj.registerD |= 0x01;
3591 ,function (parentObj) {
3592 parentObj.registerE |= 0x01;
3596 ,function (parentObj) {
3597 parentObj.registersHL |= 0x0100;
3601 ,function (parentObj) {
3602 parentObj.registersHL |= 0x01;
3606 ,function (parentObj) {
3607 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x01);
3611 ,function (parentObj) {
3612 parentObj.registerA |= 0x01;
3616 ,function (parentObj) {
3617 parentObj.registerB |= 0x02;
3621 ,function (parentObj) {
3622 parentObj.registerC |= 0x02;
3626 ,function (parentObj) {
3627 parentObj.registerD |= 0x02;
3631 ,function (parentObj) {
3632 parentObj.registerE |= 0x02;
3636 ,function (parentObj) {
3637 parentObj.registersHL |= 0x0200;
3641 ,function (parentObj) {
3642 parentObj.registersHL |= 0x02;
3646 ,function (parentObj) {
3647 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x02);
3651 ,function (parentObj) {
3652 parentObj.registerA |= 0x02;
3656 ,function (parentObj) {
3657 parentObj.registerB |= 0x04;
3661 ,function (parentObj) {
3662 parentObj.registerC |= 0x04;
3666 ,function (parentObj) {
3667 parentObj.registerD |= 0x04;
3671 ,function (parentObj) {
3672 parentObj.registerE |= 0x04;
3676 ,function (parentObj) {
3677 parentObj.registersHL |= 0x0400;
3681 ,function (parentObj) {
3682 parentObj.registersHL |= 0x04;
3686 ,function (parentObj) {
3687 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x04);
3691 ,function (parentObj) {
3692 parentObj.registerA |= 0x04;
3696 ,function (parentObj) {
3697 parentObj.registerB |= 0x08;
3701 ,function (parentObj) {
3702 parentObj.registerC |= 0x08;
3706 ,function (parentObj) {
3707 parentObj.registerD |= 0x08;
3711 ,function (parentObj) {
3712 parentObj.registerE |= 0x08;
3716 ,function (parentObj) {
3717 parentObj.registersHL |= 0x0800;
3721 ,function (parentObj) {
3722 parentObj.registersHL |= 0x08;
3726 ,function (parentObj) {
3727 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x08);
3731 ,function (parentObj) {
3732 parentObj.registerA |= 0x08;
3736 ,function (parentObj) {
3737 parentObj.registerB |= 0x10;
3741 ,function (parentObj) {
3742 parentObj.registerC |= 0x10;
3746 ,function (parentObj) {
3747 parentObj.registerD |= 0x10;
3751 ,function (parentObj) {
3752 parentObj.registerE |= 0x10;
3756 ,function (parentObj) {
3757 parentObj.registersHL |= 0x1000;
3761 ,function (parentObj) {
3762 parentObj.registersHL |= 0x10;
3766 ,function (parentObj) {
3767 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x10);
3771 ,function (parentObj) {
3772 parentObj.registerA |= 0x10;
3776 ,function (parentObj) {
3777 parentObj.registerB |= 0x20;
3781 ,function (parentObj) {
3782 parentObj.registerC |= 0x20;
3786 ,function (parentObj) {
3787 parentObj.registerD |= 0x20;
3791 ,function (parentObj) {
3792 parentObj.registerE |= 0x20;
3796 ,function (parentObj) {
3797 parentObj.registersHL |= 0x2000;
3801 ,function (parentObj) {
3802 parentObj.registersHL |= 0x20;
3806 ,function (parentObj) {
3807 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x20);
3811 ,function (parentObj) {
3812 parentObj.registerA |= 0x20;
3816 ,function (parentObj) {
3817 parentObj.registerB |= 0x40;
3821 ,function (parentObj) {
3822 parentObj.registerC |= 0x40;
3826 ,function (parentObj) {
3827 parentObj.registerD |= 0x40;
3831 ,function (parentObj) {
3832 parentObj.registerE |= 0x40;
3836 ,function (parentObj) {
3837 parentObj.registersHL |= 0x4000;
3841 ,function (parentObj) {
3842 parentObj.registersHL |= 0x40;
3846 ,function (parentObj) {
3847 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x40);
3851 ,function (parentObj) {
3852 parentObj.registerA |= 0x40;
3856 ,function (parentObj) {
3857 parentObj.registerB |= 0x80;
3861 ,function (parentObj) {
3862 parentObj.registerC |= 0x80;
3866 ,function (parentObj) {
3867 parentObj.registerD |= 0x80;
3871 ,function (parentObj) {
3872 parentObj.registerE |= 0x80;
3876 ,function (parentObj) {
3877 parentObj.registersHL |= 0x8000;
3881 ,function (parentObj) {
3882 parentObj.registersHL |= 0x80;
3886 ,function (parentObj) {
3887 parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x80);
3891 ,function (parentObj) {
3892 parentObj.registerA |= 0x80;
3895 GameBoyCore.prototype.TICKTable = [ //Number of machine cycles for each instruction:
3896 /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F*/
3897 4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4, //0
3898 4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4, //1
3899 8, 12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4, //2
3900 8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4, //3
3902 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //4
3903 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //5
3904 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //6
3905 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4, //7
3907 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //8
3908 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //9
3909 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //A
3910 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, //B
3912 8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 0, 12, 24, 8, 16, //C
3913 8, 12, 12, 4, 12, 16, 8, 16, 8, 16, 12, 4, 12, 4, 8, 16, //D
3914 12, 12, 8, 4, 4, 16, 8, 16, 16, 4, 16, 4, 4, 4, 8, 16, //E
3915 12, 12, 8, 4, 4, 16, 8, 16, 12, 8, 16, 4, 0, 4, 8, 16 //F
3917 GameBoyCore.prototype.SecondaryTICKTable = [ //Number of machine cycles for each 0xCBXX instruction:
3918 /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F*/
3919 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //0
3920 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //1
3921 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //2
3922 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //3
3924 8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, //4
3925 8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, //5
3926 8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, //6
3927 8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, //7
3929 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //8
3930 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //9
3931 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //A
3932 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //B
3934 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //C
3935 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //D
3936 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, //E
3937 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8 //F
3939 GameBoyCore.prototype.saveSRAMState = function () {
3940 if (!this.cBATT || this.MBCRam.length == 0) {
3941 //No battery backup...
3945 //Return the MBC RAM for backup...
3946 return this.fromTypedArray(this.MBCRam);
3949 GameBoyCore.prototype.saveRTCState = function () {
3951 //No battery backup...
3955 //Return the MBC RAM for backup...
3959 this.latchedSeconds,
3960 this.latchedMinutes,
3968 this.RTCDayOverFlow,
3973 GameBoyCore.prototype.saveState = function () {
3975 this.fromTypedArray(this.ROM),
3988 this.programCounter,
3993 this.doubleSpeedShifter,
3994 this.fromTypedArray(this.memory),
3995 this.fromTypedArray(this.MBCRam),
3996 this.fromTypedArray(this.VRAM),
3998 this.fromTypedArray(this.GBCMemory),
4000 this.MBCRAMBanksEnabled,
4001 this.currMBCRAMBank,
4002 this.currMBCRAMBankPosition,
4005 this.gbcRamBankPosition,
4007 this.currentROMBank,
4012 this.LYCMatchTriggerSTAT,
4013 this.mode2TriggerSTAT,
4014 this.mode1TriggerSTAT,
4015 this.mode0TriggerSTAT,
4017 this.gfxWindowCHRBankPosition,
4018 this.gfxWindowDisplay,
4020 this.gfxSpriteNormalHeight,
4021 this.gfxBackgroundCHRBankPosition,
4022 this.gfxBackgroundBankOffset,
4029 this.serialShiftTimer,
4030 this.serialShiftTimerAllocated,
4031 this.IRQEnableDelay,
4046 this.fromTypedArray(this.frameBuffer),
4048 this.BGPriorityEnabled,
4049 this.channel1FrequencyTracker,
4050 this.channel1FrequencyCounter,
4051 this.channel1totalLength,
4052 this.channel1envelopeVolume,
4053 this.channel1envelopeType,
4054 this.channel1envelopeSweeps,
4055 this.channel1envelopeSweepsLast,
4056 this.channel1consecutive,
4057 this.channel1frequency,
4058 this.channel1SweepFault,
4059 this.channel1ShadowFrequency,
4060 this.channel1timeSweep,
4061 this.channel1lastTimeSweep,
4062 this.channel1numSweep,
4063 this.channel1frequencySweepDivider,
4064 this.channel1decreaseSweep,
4065 this.channel2FrequencyTracker,
4066 this.channel2FrequencyCounter,
4067 this.channel2totalLength,
4068 this.channel2envelopeVolume,
4069 this.channel2envelopeType,
4070 this.channel2envelopeSweeps,
4071 this.channel2envelopeSweepsLast,
4072 this.channel2consecutive,
4073 this.channel2frequency,
4074 this.channel3canPlay,
4075 this.channel3totalLength,
4076 this.channel3patternType,
4077 this.channel3frequency,
4078 this.channel3consecutive,
4079 this.fromTypedArray(this.channel3PCM),
4080 this.channel4FrequencyPeriod,
4081 this.channel4lastSampleLookup,
4082 this.channel4totalLength,
4083 this.channel4envelopeVolume,
4084 this.channel4currentVolume,
4085 this.channel4envelopeType,
4086 this.channel4envelopeSweeps,
4087 this.channel4envelopeSweepsLast,
4088 this.channel4consecutive,
4089 this.channel4BitRange,
4090 this.soundMasterEnabled,
4091 this.VinLeftChannelMasterVolume,
4092 this.VinRightChannelMasterVolume,
4101 this.channel1currentSampleLeft,
4102 this.channel1currentSampleRight,
4103 this.channel2currentSampleLeft,
4104 this.channel2currentSampleRight,
4105 this.channel3currentSampleLeft,
4106 this.channel3currentSampleRight,
4107 this.channel4currentSampleLeft,
4108 this.channel4currentSampleRight,
4109 this.channel1currentSampleLeftSecondary,
4110 this.channel1currentSampleRightSecondary,
4111 this.channel2currentSampleLeftSecondary,
4112 this.channel2currentSampleRightSecondary,
4113 this.channel3currentSampleLeftSecondary,
4114 this.channel3currentSampleRightSecondary,
4115 this.channel4currentSampleLeftSecondary,
4116 this.channel4currentSampleRightSecondary,
4117 this.channel1currentSampleLeftTrimary,
4118 this.channel1currentSampleRightTrimary,
4119 this.channel2currentSampleLeftTrimary,
4120 this.channel2currentSampleRightTrimary,
4121 this.mixerOutputCache,
4122 this.channel1DutyTracker,
4123 this.channel1CachedDuty,
4124 this.channel2DutyTracker,
4125 this.channel2CachedDuty,
4126 this.channel1Enabled,
4127 this.channel2Enabled,
4128 this.channel3Enabled,
4129 this.channel4Enabled,
4130 this.sequencerClocks,
4131 this.sequencePosition,
4132 this.channel3Counter,
4133 this.channel4Counter,
4134 this.cachedChannel3Sample,
4135 this.cachedChannel4Sample,
4136 this.channel3FrequencyPeriod,
4137 this.channel3lastSampleLookup,
4138 this.actualScanLine,
4139 this.lastUnrenderedLine,
4140 this.queuedScanLines,
4142 this.latchedSeconds,
4143 this.latchedMinutes,
4151 this.RTCDayOverFlow,
4154 this.skipPCIncrement,
4156 this.gbcRamBankPositionECHO,
4160 this.fromTypedArray(this.gbcOBJRawPalette),
4161 this.fromTypedArray(this.gbcBGRawPalette),
4162 this.fromTypedArray(this.gbOBJPalette),
4163 this.fromTypedArray(this.gbBGPalette),
4164 this.fromTypedArray(this.gbcOBJPalette),
4165 this.fromTypedArray(this.gbcBGPalette),
4166 this.fromTypedArray(this.gbBGColorizedPalette),
4167 this.fromTypedArray(this.gbOBJColorizedPalette),
4168 this.fromTypedArray(this.cachedBGPaletteConversion),
4169 this.fromTypedArray(this.cachedOBJPaletteConversion),
4170 this.fromTypedArray(this.BGCHRBank1),
4171 this.fromTypedArray(this.BGCHRBank2),
4172 this.haltPostClocks,
4173 this.interruptsRequested,
4174 this.interruptsEnabled,
4175 this.remainingClocks,
4176 this.colorizedGBPalettes,
4182 GameBoyCore.prototype.returnFromState = function (returnedFrom) {
4184 var state = returnedFrom.slice(0);
4185 this.ROM = this.toTypedArray(state[index++], "uint8");
4186 this.ROMBankEdge = Math.floor(this.ROM.length / 0x4000);
4187 this.inBootstrap = state[index++];
4188 this.registerA = state[index++];
4189 this.FZero = state[index++];
4190 this.FSubtract = state[index++];
4191 this.FHalfCarry = state[index++];
4192 this.FCarry = state[index++];
4193 this.registerB = state[index++];
4194 this.registerC = state[index++];
4195 this.registerD = state[index++];
4196 this.registerE = state[index++];
4197 this.registersHL = state[index++];
4198 this.stackPointer = state[index++];
4199 this.programCounter = state[index++];
4200 this.halt = state[index++];
4201 this.IME = state[index++];
4202 this.hdmaRunning = state[index++];
4203 this.CPUTicks = state[index++];
4204 this.doubleSpeedShifter = state[index++];
4205 this.memory = this.toTypedArray(state[index++], "uint8");
4206 this.MBCRam = this.toTypedArray(state[index++], "uint8");
4207 this.VRAM = this.toTypedArray(state[index++], "uint8");
4208 this.currVRAMBank = state[index++];
4209 this.GBCMemory = this.toTypedArray(state[index++], "uint8");
4210 this.MBC1Mode = state[index++];
4211 this.MBCRAMBanksEnabled = state[index++];
4212 this.currMBCRAMBank = state[index++];
4213 this.currMBCRAMBankPosition = state[index++];
4214 this.cGBC = state[index++];
4215 this.gbcRamBank = state[index++];
4216 this.gbcRamBankPosition = state[index++];
4217 this.ROMBank1offs = state[index++];
4218 this.currentROMBank = state[index++];
4219 this.cartridgeType = state[index++];
4220 this.name = state[index++];
4221 this.gameCode = state[index++];
4222 this.modeSTAT = state[index++];
4223 this.LYCMatchTriggerSTAT = state[index++];
4224 this.mode2TriggerSTAT = state[index++];
4225 this.mode1TriggerSTAT = state[index++];
4226 this.mode0TriggerSTAT = state[index++];
4227 this.LCDisOn = state[index++];
4228 this.gfxWindowCHRBankPosition = state[index++];
4229 this.gfxWindowDisplay = state[index++];
4230 this.gfxSpriteShow = state[index++];
4231 this.gfxSpriteNormalHeight = state[index++];
4232 this.gfxBackgroundCHRBankPosition = state[index++];
4233 this.gfxBackgroundBankOffset = state[index++];
4234 this.TIMAEnabled = state[index++];
4235 this.DIVTicks = state[index++];
4236 this.LCDTicks = state[index++];
4237 this.timerTicks = state[index++];
4238 this.TACClocker = state[index++];
4239 this.serialTimer = state[index++];
4240 this.serialShiftTimer = state[index++];
4241 this.serialShiftTimerAllocated = state[index++];
4242 this.IRQEnableDelay = state[index++];
4243 this.lastIteration = state[index++];
4244 this.cMBC1 = state[index++];
4245 this.cMBC2 = state[index++];
4246 this.cMBC3 = state[index++];
4247 this.cMBC5 = state[index++];
4248 this.cMBC7 = state[index++];
4249 this.cSRAM = state[index++];
4250 this.cMMMO1 = state[index++];
4251 this.cRUMBLE = state[index++];
4252 this.cCamera = state[index++];
4253 this.cTAMA5 = state[index++];
4254 this.cHuC3 = state[index++];
4255 this.cHuC1 = state[index++];
4256 this.drewBlank = state[index++];
4257 this.frameBuffer = this.toTypedArray(state[index++], "int32");
4258 this.bgEnabled = state[index++];
4259 this.BGPriorityEnabled = state[index++];
4260 this.channel1FrequencyTracker = state[index++];
4261 this.channel1FrequencyCounter = state[index++];
4262 this.channel1totalLength = state[index++];
4263 this.channel1envelopeVolume = state[index++];
4264 this.channel1envelopeType = state[index++];
4265 this.channel1envelopeSweeps = state[index++];
4266 this.channel1envelopeSweepsLast = state[index++];
4267 this.channel1consecutive = state[index++];
4268 this.channel1frequency = state[index++];
4269 this.channel1SweepFault = state[index++];
4270 this.channel1ShadowFrequency = state[index++];
4271 this.channel1timeSweep = state[index++];
4272 this.channel1lastTimeSweep = state[index++];
4273 this.channel1numSweep = state[index++];
4274 this.channel1frequencySweepDivider = state[index++];
4275 this.channel1decreaseSweep = state[index++];
4276 this.channel2FrequencyTracker = state[index++];
4277 this.channel2FrequencyCounter = state[index++];
4278 this.channel2totalLength = state[index++];
4279 this.channel2envelopeVolume = state[index++];
4280 this.channel2envelopeType = state[index++];
4281 this.channel2envelopeSweeps = state[index++];
4282 this.channel2envelopeSweepsLast = state[index++];
4283 this.channel2consecutive = state[index++];
4284 this.channel2frequency = state[index++];
4285 this.channel3canPlay = state[index++];
4286 this.channel3totalLength = state[index++];
4287 this.channel3patternType = state[index++];
4288 this.channel3frequency = state[index++];
4289 this.channel3consecutive = state[index++];
4290 this.channel3PCM = this.toTypedArray(state[index++], "int8");
4291 this.channel4FrequencyPeriod = state[index++];
4292 this.channel4lastSampleLookup = state[index++];
4293 this.channel4totalLength = state[index++];
4294 this.channel4envelopeVolume = state[index++];
4295 this.channel4currentVolume = state[index++];
4296 this.channel4envelopeType = state[index++];
4297 this.channel4envelopeSweeps = state[index++];
4298 this.channel4envelopeSweepsLast = state[index++];
4299 this.channel4consecutive = state[index++];
4300 this.channel4BitRange = state[index++];
4301 this.soundMasterEnabled = state[index++];
4302 this.VinLeftChannelMasterVolume = state[index++];
4303 this.VinRightChannelMasterVolume = state[index++];
4304 this.leftChannel1 = state[index++];
4305 this.leftChannel2 = state[index++];
4306 this.leftChannel3 = state[index++];
4307 this.leftChannel4 = state[index++];
4308 this.rightChannel1 = state[index++];
4309 this.rightChannel2 = state[index++];
4310 this.rightChannel3 = state[index++];
4311 this.rightChannel4 = state[index++];
4312 this.channel1currentSampleLeft = state[index++];
4313 this.channel1currentSampleRight = state[index++];
4314 this.channel2currentSampleLeft = state[index++];
4315 this.channel2currentSampleRight = state[index++];
4316 this.channel3currentSampleLeft = state[index++];
4317 this.channel3currentSampleRight = state[index++];
4318 this.channel4currentSampleLeft = state[index++];
4319 this.channel4currentSampleRight = state[index++];
4320 this.channel1currentSampleLeftSecondary = state[index++];
4321 this.channel1currentSampleRightSecondary = state[index++];
4322 this.channel2currentSampleLeftSecondary = state[index++];
4323 this.channel2currentSampleRightSecondary = state[index++];
4324 this.channel3currentSampleLeftSecondary = state[index++];
4325 this.channel3currentSampleRightSecondary = state[index++];
4326 this.channel4currentSampleLeftSecondary = state[index++];
4327 this.channel4currentSampleRightSecondary = state[index++];
4328 this.channel1currentSampleLeftTrimary = state[index++];
4329 this.channel1currentSampleRightTrimary = state[index++];
4330 this.channel2currentSampleLeftTrimary = state[index++];
4331 this.channel2currentSampleRightTrimary = state[index++];
4332 this.mixerOutputCache = state[index++];
4333 this.channel1DutyTracker = state[index++];
4334 this.channel1CachedDuty = state[index++];
4335 this.channel2DutyTracker = state[index++];
4336 this.channel2CachedDuty = state[index++];
4337 this.channel1Enabled = state[index++];
4338 this.channel2Enabled = state[index++];
4339 this.channel3Enabled = state[index++];
4340 this.channel4Enabled = state[index++];
4341 this.sequencerClocks = state[index++];
4342 this.sequencePosition = state[index++];
4343 this.channel3Counter = state[index++];
4344 this.channel4Counter = state[index++];
4345 this.cachedChannel3Sample = state[index++];
4346 this.cachedChannel4Sample = state[index++];
4347 this.channel3FrequencyPeriod = state[index++];
4348 this.channel3lastSampleLookup = state[index++];
4349 this.actualScanLine = state[index++];
4350 this.lastUnrenderedLine = state[index++];
4351 this.queuedScanLines = state[index++];
4352 this.RTCisLatched = state[index++];
4353 this.latchedSeconds = state[index++];
4354 this.latchedMinutes = state[index++];
4355 this.latchedHours = state[index++];
4356 this.latchedLDays = state[index++];
4357 this.latchedHDays = state[index++];
4358 this.RTCSeconds = state[index++];
4359 this.RTCMinutes = state[index++];
4360 this.RTCHours = state[index++];
4361 this.RTCDays = state[index++];
4362 this.RTCDayOverFlow = state[index++];
4363 this.RTCHALT = state[index++];
4364 this.usedBootROM = state[index++];
4365 this.skipPCIncrement = state[index++];
4366 this.STATTracker = state[index++];
4367 this.gbcRamBankPositionECHO = state[index++];
4368 this.numRAMBanks = state[index++];
4369 this.windowY = state[index++];
4370 this.windowX = state[index++];
4371 this.gbcOBJRawPalette = this.toTypedArray(state[index++], "uint8");
4372 this.gbcBGRawPalette = this.toTypedArray(state[index++], "uint8");
4373 this.gbOBJPalette = this.toTypedArray(state[index++], "int32");
4374 this.gbBGPalette = this.toTypedArray(state[index++], "int32");
4375 this.gbcOBJPalette = this.toTypedArray(state[index++], "int32");
4376 this.gbcBGPalette = this.toTypedArray(state[index++], "int32");
4377 this.gbBGColorizedPalette = this.toTypedArray(state[index++], "int32");
4378 this.gbOBJColorizedPalette = this.toTypedArray(state[index++], "int32");
4379 this.cachedBGPaletteConversion = this.toTypedArray(state[index++], "int32");
4380 this.cachedOBJPaletteConversion = this.toTypedArray(state[index++], "int32");
4381 this.BGCHRBank1 = this.toTypedArray(state[index++], "uint8");
4382 this.BGCHRBank2 = this.toTypedArray(state[index++], "uint8");
4383 this.haltPostClocks = state[index++];
4384 this.interruptsRequested = state[index++];
4385 this.interruptsEnabled = state[index++];
4386 this.checkIRQMatching();
4387 this.remainingClocks = state[index++];
4388 this.colorizedGBPalettes = state[index++];
4389 this.backgroundY = state[index++];
4390 this.backgroundX = state[index++];
4391 this.CPUStopped = state[index];
4392 this.fromSaveState = true;
4393 this.TICKTable = this.toTypedArray(this.TICKTable, "uint8");
4394 this.SecondaryTICKTable = this.toTypedArray(this.SecondaryTICKTable, "uint8");
4395 this.initializeReferencesFromSaveState();
4396 this.memoryReadJumpCompile();
4397 this.memoryWriteJumpCompile();
4400 this.noiseSampleTable = (this.channel4BitRange == 0x7FFF) ? this.LSFR15Table : this.LSFR7Table;
4401 this.channel4VolumeShifter = (this.channel4BitRange == 0x7FFF) ? 15 : 7;
4403 GameBoyCore.prototype.returnFromRTCState = function () {
4404 if (typeof this.openRTC == "function" && this.cTIMER) {
4405 var rtcData = this.openRTC(this.name);
4407 this.lastIteration = rtcData[index++];
4408 this.RTCisLatched = rtcData[index++];
4409 this.latchedSeconds = rtcData[index++];
4410 this.latchedMinutes = rtcData[index++];
4411 this.latchedHours = rtcData[index++];
4412 this.latchedLDays = rtcData[index++];
4413 this.latchedHDays = rtcData[index++];
4414 this.RTCSeconds = rtcData[index++];
4415 this.RTCMinutes = rtcData[index++];
4416 this.RTCHours = rtcData[index++];
4417 this.RTCDays = rtcData[index++];
4418 this.RTCDayOverFlow = rtcData[index++];
4419 this.RTCHALT = rtcData[index];
4423 GameBoyCore.prototype.start = function () {
4424 this.initMemory(); //Write the startup memory.
4425 this.ROMLoad(); //Load the ROM into memory and get cartridge information from it.
4426 this.initLCD(); //Initialize the graphics.
4427 this.initSound(); //Sound object initialization.
4428 this.run(); //Start the emulation.
4430 GameBoyCore.prototype.initMemory = function () {
4431 //Initialize the RAM:
4432 this.memory = this.getTypedArray(0x10000, 0, "uint8");
4433 this.frameBuffer = this.getTypedArray(23040, 0xF8F8F8, "int32");
4434 this.BGCHRBank1 = this.getTypedArray(0x800, 0, "uint8");
4435 this.TICKTable = this.toTypedArray(this.TICKTable, "uint8");
4436 this.SecondaryTICKTable = this.toTypedArray(this.SecondaryTICKTable, "uint8");
4437 this.channel3PCM = this.getTypedArray(0x20, 0, "int8");
4439 GameBoyCore.prototype.generateCacheArray = function (tileAmount) {
4442 while (tileNumber < tileAmount) {
4443 tileArray[tileNumber++] = this.getTypedArray(64, 0, "uint8");
4447 GameBoyCore.prototype.initSkipBootstrap = function () {
4448 //Fill in the boot ROM set register values
4449 //Default values to the GB boot ROM values, then fill in the GBC boot ROM values after ROM loading
4451 while (index >= 0) {
4452 if (index >= 0x30 && index < 0x40) {
4453 this.memoryWrite(0xFF00 | index, this.ffxxDump[index]);
4464 this.memoryWrite(0xFF00 | index, this.ffxxDump[index]);
4467 this.memory[0xFF00 | index] = this.ffxxDump[index];
4473 this.memory[0xFF6C] = 0xFE;
4474 this.memory[0xFF74] = 0xFE;
4477 this.memory[0xFF48] = 0xFF;
4478 this.memory[0xFF49] = 0xFF;
4479 this.memory[0xFF6C] = 0xFF;
4480 this.memory[0xFF74] = 0xFF;
4482 //Start as an unset device:
4483 cout("Starting without the GBC boot ROM.", 0);
4484 this.registerA = (this.cGBC) ? 0x11 : 0x1;
4486 this.registerC = 0x13;
4488 this.registerE = 0xD8;
4490 this.FSubtract = false;
4491 this.FHalfCarry = true;
4493 this.registersHL = 0x014D;
4494 this.LCDCONTROL = this.LINECONTROL;
4496 this.IRQLineMatched = 0;
4497 this.interruptsRequested = 225;
4498 this.interruptsEnabled = 0;
4499 this.hdmaRunning = false;
4501 this.STATTracker = 0;
4503 this.spriteCount = 252;
4504 this.LYCMatchTriggerSTAT = false;
4505 this.mode2TriggerSTAT = false;
4506 this.mode1TriggerSTAT = false;
4507 this.mode0TriggerSTAT = false;
4508 this.LCDisOn = true;
4509 this.channel1FrequencyTracker = 0x2000;
4510 this.channel1DutyTracker = 0;
4511 this.channel1CachedDuty = this.dutyLookup[2];
4512 this.channel1totalLength = 0;
4513 this.channel1envelopeVolume = 0;
4514 this.channel1envelopeType = false;
4515 this.channel1envelopeSweeps = 0;
4516 this.channel1envelopeSweepsLast = 0;
4517 this.channel1consecutive = true;
4518 this.channel1frequency = 1985;
4519 this.channel1SweepFault = true;
4520 this.channel1ShadowFrequency = 1985;
4521 this.channel1timeSweep = 1;
4522 this.channel1lastTimeSweep = 0;
4523 this.channel1numSweep = 0;
4524 this.channel1frequencySweepDivider = 0;
4525 this.channel1decreaseSweep = false;
4526 this.channel2FrequencyTracker = 0x2000;
4527 this.channel2DutyTracker = 0;
4528 this.channel2CachedDuty = this.dutyLookup[2];
4529 this.channel2totalLength = 0;
4530 this.channel2envelopeVolume = 0;
4531 this.channel2envelopeType = false;
4532 this.channel2envelopeSweeps = 0;
4533 this.channel2envelopeSweepsLast = 0;
4534 this.channel2consecutive = true;
4535 this.channel2frequency = 0;
4536 this.channel3canPlay = false;
4537 this.channel3totalLength = 0;
4538 this.channel3patternType = 4;
4539 this.channel3frequency = 0;
4540 this.channel3consecutive = true;
4541 this.channel3Counter = 0x418;
4542 this.channel4FrequencyPeriod = 8;
4543 this.channel4totalLength = 0;
4544 this.channel4envelopeVolume = 0;
4545 this.channel4currentVolume = 0;
4546 this.channel4envelopeType = false;
4547 this.channel4envelopeSweeps = 0;
4548 this.channel4envelopeSweepsLast = 0;
4549 this.channel4consecutive = true;
4550 this.channel4BitRange = 0x7FFF;
4551 this.channel4VolumeShifter = 15;
4552 this.channel1FrequencyCounter = 0x200;
4553 this.channel2FrequencyCounter = 0x200;
4554 this.channel3Counter = 0x800;
4555 this.channel3FrequencyPeriod = 0x800;
4556 this.channel3lastSampleLookup = 0;
4557 this.channel4lastSampleLookup = 0;
4558 this.VinLeftChannelMasterVolume = 1;
4559 this.VinRightChannelMasterVolume = 1;
4560 this.soundMasterEnabled = true;
4561 this.leftChannel1 = true;
4562 this.leftChannel2 = true;
4563 this.leftChannel3 = true;
4564 this.leftChannel4 = true;
4565 this.rightChannel1 = true;
4566 this.rightChannel2 = true;
4567 this.rightChannel3 = false;
4568 this.rightChannel4 = false;
4569 this.DIVTicks = 27044;
4570 this.LCDTicks = 160;
4571 this.timerTicks = 0;
4572 this.TIMAEnabled = false;
4573 this.TACClocker = 1024;
4574 this.serialTimer = 0;
4575 this.serialShiftTimer = 0;
4576 this.serialShiftTimerAllocated = 0;
4577 this.IRQEnableDelay = 0;
4578 this.actualScanLine = 144;
4579 this.lastUnrenderedLine = 0;
4580 this.gfxWindowDisplay = false;
4581 this.gfxSpriteShow = false;
4582 this.gfxSpriteNormalHeight = true;
4583 this.bgEnabled = true;
4584 this.BGPriorityEnabled = true;
4585 this.gfxWindowCHRBankPosition = 0;
4586 this.gfxBackgroundCHRBankPosition = 0;
4587 this.gfxBackgroundBankOffset = 0;
4591 this.midScanlineOffset = -1;
4594 GameBoyCore.prototype.initBootstrap = function () {
4595 //Start as an unset device:
4596 cout("Starting the selected boot ROM.", 0);
4597 this.programCounter = 0;
4598 this.stackPointer = 0;
4607 this.FZero = this.FSubtract = this.FHalfCarry = this.FCarry = false;
4608 this.registersHL = 0;
4609 this.leftChannel1 = false;
4610 this.leftChannel2 = false;
4611 this.leftChannel3 = false;
4612 this.leftChannel4 = false;
4613 this.rightChannel1 = false;
4614 this.rightChannel2 = false;
4615 this.rightChannel3 = false;
4616 this.rightChannel4 = false;
4617 this.channel2frequency = this.channel1frequency = 0;
4618 this.channel4consecutive = this.channel2consecutive = this.channel1consecutive = false;
4619 this.VinLeftChannelMasterVolume = 8;
4620 this.VinRightChannelMasterVolume = 8;
4621 this.memory[0xFF00] = 0xF; //Set the joypad state.
4623 GameBoyCore.prototype.ROMLoad = function () {
4624 //Load the first two ROM banks (0x0000 - 0x7FFF) into regular gameboy memory:
4626 this.usedBootROM = settings[1];
4627 var maxLength = this.ROMImage.length;
4628 if (maxLength < 0x4000) {
4629 throw(new Error("ROM image size too small."));
4631 this.ROM = this.getTypedArray(maxLength, 0, "uint8");
4633 if (this.usedBootROM) {
4634 if (!settings[11]) {
4635 //Patch in the GBC boot ROM into the memory map:
4636 for (; romIndex < 0x100; ++romIndex) {
4637 this.memory[romIndex] = this.GBCBOOTROM[romIndex]; //Load in the GameBoy Color BOOT ROM.
4638 this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF); //Decode the ROM binary for the switch out.
4640 for (; romIndex < 0x200; ++romIndex) {
4641 this.memory[romIndex] = this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF); //Load in the game ROM.
4643 for (; romIndex < 0x900; ++romIndex) {
4644 this.memory[romIndex] = this.GBCBOOTROM[romIndex - 0x100]; //Load in the GameBoy Color BOOT ROM.
4645 this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF); //Decode the ROM binary for the switch out.
4647 this.usedGBCBootROM = true;
4650 //Patch in the GBC boot ROM into the memory map:
4651 for (; romIndex < 0x100; ++romIndex) {
4652 this.memory[romIndex] = this.GBBOOTROM[romIndex]; //Load in the GameBoy Color BOOT ROM.
4653 this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF); //Decode the ROM binary for the switch out.
4656 for (; romIndex < 0x4000; ++romIndex) {
4657 this.memory[romIndex] = this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF); //Load in the game ROM.
4661 //Don't load in the boot ROM:
4662 for (; romIndex < 0x4000; ++romIndex) {
4663 this.memory[romIndex] = this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF); //Load in the game ROM.
4666 //Finish the decoding of the ROM binary:
4667 for (; romIndex < maxLength; ++romIndex) {
4668 this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);
4670 this.ROMBankEdge = Math.floor(this.ROM.length / 0x4000);
4671 //Set up the emulator for the cartidge specifics:
4672 this.interpretCartridge();
4673 //Check for IRQ matching upon initialization:
4674 this.checkIRQMatching();
4676 GameBoyCore.prototype.getROMImage = function () {
4677 //Return the binary version of the ROM image currently running:
4678 if (this.ROMImage.length > 0) {
4679 return this.ROMImage.length;
4681 var length = this.ROM.length;
4682 for (var index = 0; index < length; index++) {
4683 this.ROMImage += String.fromCharCode(this.ROM[index]);
4685 return this.ROMImage;
4687 GameBoyCore.prototype.interpretCartridge = function () {
4689 for (var index = 0x134; index < 0x13F; index++) {
4690 if (this.ROMImage.charCodeAt(index) > 0) {
4691 this.name += this.ROMImage[index];
4694 // ROM game code (for newer games)
4695 for (var index = 0x13F; index < 0x143; index++) {
4696 if (this.ROMImage.charCodeAt(index) > 0) {
4697 this.gameCode += this.ROMImage[index];
4700 cout("Game Title: " + this.name + "[" + this.gameCode + "][" + this.ROMImage[0x143] + "]", 0);
4701 cout("Game Code: " + this.gameCode, 0);
4703 this.cartridgeType = this.ROM[0x147];
4704 cout("Cartridge type #" + this.cartridgeType, 0);
4705 //Map out ROM cartridge sub-types.
4707 switch (this.cartridgeType) {
4709 //ROM w/o bank switching
4721 MBCType = "MBC1 + SRAM";
4727 MBCType = "MBC1 + SRAM + BATT";
4736 MBCType = "MBC2 + BATT";
4740 MBCType = "ROM + SRAM";
4745 MBCType = "ROM + SRAM + BATT";
4754 MBCType = "MMMO1 + SRAM";
4760 MBCType = "MMMO1 + SRAM + BATT";
4766 MBCType = "MBC3 + TIMER + BATT";
4773 MBCType = "MBC3 + TIMER + BATT + SRAM";
4782 MBCType = "MBC3 + SRAM";
4788 MBCType = "MBC3 + SRAM + BATT";
4797 MBCType = "MBC5 + SRAM";
4803 MBCType = "MBC5 + SRAM + BATT";
4806 this.cRUMBLE = true;
4810 this.cRUMBLE = true;
4812 MBCType = "RUMBLE + SRAM";
4815 this.cRUMBLE = true;
4818 MBCType = "RUMBLE + SRAM + BATT";
4821 this.cCamera = true;
4822 MBCType = "GameBoy Camera";
4828 MBCType = "MBC7 + SRAM + BATT";
4843 MBCType = "Unknown";
4844 cout("Cartridge type is unknown.", 2);
4847 cout("Cartridge Type: " + MBCType + ".", 0);
4848 // ROM and RAM banks
4849 this.numROMBanks = this.ROMBanks[this.ROM[0x148]];
4850 cout(this.numROMBanks + " ROM banks.", 0);
4851 switch (this.RAMBanks[this.ROM[0x149]]) {
4853 cout("No RAM banking requested for allocation or MBC is of type 2.", 0);
4856 cout("1 RAM bank requested for allocation.", 0);
4859 cout("4 RAM banks requested for allocation.", 0);
4862 cout("16 RAM banks requested for allocation.", 0);
4865 cout("RAM bank amount requested is unknown, will use maximum allowed by specified MBC type.", 0);
4867 //Check the GB/GBC mode byte:
4868 if (!this.usedBootROM) {
4869 switch (this.ROM[0x143]) {
4870 case 0x00: //Only GB mode
4872 cout("Only GB mode detected.", 0);
4874 case 0x32: //Exception to the GBC identifying code:
4875 if (!settings[2] && this.name + this.gameCode + this.ROM[0x143] == "Game and Watch 50") {
4877 cout("Created a boot exception for Game and Watch Gallery 2 (GBC ID byte is wrong on the cartridge).", 1);
4883 case 0x80: //Both GB + GBC modes
4884 this.cGBC = !settings[2];
4885 cout("GB and GBC mode detected.", 0);
4887 case 0xC0: //Only GBC mode
4889 cout("Only GBC mode detected.", 0);
4893 cout("Unknown GameBoy game type code #" + this.ROM[0x143] + ", defaulting to GB mode (Old games don't have a type code).", 1);
4895 this.inBootstrap = false;
4896 this.setupRAM(); //CPU/(V)RAM initialization.
4897 this.initSkipBootstrap();
4898 this.initializeAudioStartState(); // Line added for benchmarking.
4901 this.cGBC = this.usedGBCBootROM; //Allow the GBC boot ROM to run in GBC mode...
4902 this.setupRAM(); //CPU/(V)RAM initialization.
4903 this.initBootstrap();
4905 this.initializeModeSpecificArrays();
4906 //License Code Lookup:
4907 var cOldLicense = this.ROM[0x14B];
4908 var cNewLicense = (this.ROM[0x144] & 0xFF00) | (this.ROM[0x145] & 0xFF);
4909 if (cOldLicense != 0x33) {
4910 //Old Style License Header
4911 cout("Old style license code: " + cOldLicense, 0);
4914 //New Style License Header
4915 cout("New style license code: " + cNewLicense, 0);
4917 this.ROMImage = ""; //Memory consumption reduction.
4919 GameBoyCore.prototype.disableBootROM = function () {
4920 //Remove any traces of the boot ROM from ROM memory.
4921 for (var index = 0; index < 0x100; ++index) {
4922 this.memory[index] = this.ROM[index]; //Replace the GameBoy or GameBoy Color boot ROM with the game ROM.
4924 if (this.usedGBCBootROM) {
4925 //Remove any traces of the boot ROM from ROM memory.
4926 for (index = 0x200; index < 0x900; ++index) {
4927 this.memory[index] = this.ROM[index]; //Replace the GameBoy Color boot ROM with the game ROM.
4930 //Clean up the post-boot (GB mode only) state:
4931 this.GBCtoGBModeAdjust();
4934 this.recompileBootIOWriteHandling();
4938 this.recompileBootIOWriteHandling();
4941 GameBoyCore.prototype.initializeTiming = function () {
4943 this.baseCPUCyclesPerIteration = 0x80000 / 0x7D * settings[6];
4944 this.CPUCyclesTotalRoundoff = this.baseCPUCyclesPerIteration % 4;
4945 this.CPUCyclesTotalBase = this.CPUCyclesTotal = (this.baseCPUCyclesPerIteration - this.CPUCyclesTotalRoundoff) | 0;
4946 this.CPUCyclesTotalCurrent = 0;
4948 GameBoyCore.prototype.setupRAM = function () {
4949 //Setup the auxilliary/switchable RAM:
4951 this.numRAMBanks = 1 / 16;
4953 else if (this.cMBC1 || this.cRUMBLE || this.cMBC3 || this.cHuC3) {
4954 this.numRAMBanks = 4;
4956 else if (this.cMBC5) {
4957 this.numRAMBanks = 16;
4959 else if (this.cSRAM) {
4960 this.numRAMBanks = 1;
4962 if (this.numRAMBanks > 0) {
4963 if (!this.MBCRAMUtilized()) {
4964 //For ROM and unknown MBC cartridges using the external RAM:
4965 this.MBCRAMBanksEnabled = true;
4968 var MBCRam = (typeof this.openMBC == "function") ? this.openMBC(this.name) : [];
4969 if (MBCRam.length > 0) {
4970 //Flash the SRAM into memory:
4971 this.MBCRam = this.toTypedArray(MBCRam, "uint8");
4974 this.MBCRam = this.getTypedArray(this.numRAMBanks * 0x2000, 0, "uint8");
4977 cout("Actual bytes of MBC RAM allocated: " + (this.numRAMBanks * 0x2000), 0);
4978 this.returnFromRTCState();
4979 //Setup the RAM for GBC mode.
4981 this.VRAM = this.getTypedArray(0x2000, 0, "uint8");
4982 this.GBCMemory = this.getTypedArray(0x7000, 0, "uint8");
4984 this.memoryReadJumpCompile();
4985 this.memoryWriteJumpCompile();
4987 GameBoyCore.prototype.MBCRAMUtilized = function () {
4988 return this.cMBC1 || this.cMBC2 || this.cMBC3 || this.cMBC5 || this.cMBC7 || this.cRUMBLE;
4990 GameBoyCore.prototype.recomputeDimension = function () {
4992 //Cache some dimension info:
4993 this.onscreenWidth = this.canvas.width;
4994 this.onscreenHeight = this.canvas.height;
4995 // The following line was modified for benchmarking:
4996 if (GameBoyWindow && GameBoyWindow.mozRequestAnimationFrame) {
4997 //Firefox slowness hack:
4998 this.canvas.width = this.onscreenWidth = (!settings[12]) ? 160 : this.canvas.width;
4999 this.canvas.height = this.onscreenHeight = (!settings[12]) ? 144 : this.canvas.height;
5002 this.onscreenWidth = this.canvas.width;
5003 this.onscreenHeight = this.canvas.height;
5005 this.offscreenWidth = (!settings[12]) ? 160 : this.canvas.width;
5006 this.offscreenHeight = (!settings[12]) ? 144 : this.canvas.height;
5007 this.offscreenRGBCount = this.offscreenWidth * this.offscreenHeight * 4;
5009 GameBoyCore.prototype.initLCD = function () {
5010 this.recomputeDimension();
5011 if (this.offscreenRGBCount != 92160) {
5012 //Only create the resizer handle if we need it:
5013 this.compileResizeFrameBufferFunction();
5016 //Resizer not needed:
5017 this.resizer = null;
5020 this.canvasOffscreen = new GameBoyCanvas(); // Line modified for benchmarking.
5021 this.canvasOffscreen.width = this.offscreenWidth;
5022 this.canvasOffscreen.height = this.offscreenHeight;
5023 this.drawContextOffscreen = this.canvasOffscreen.getContext("2d");
5024 this.drawContextOnscreen = this.canvas.getContext("2d");
5025 //Get a CanvasPixelArray buffer:
5027 this.canvasBuffer = this.drawContextOffscreen.createImageData(this.offscreenWidth, this.offscreenHeight);
5030 cout("Falling back to the getImageData initialization (Error \"" + error.message + "\").", 1);
5031 this.canvasBuffer = this.drawContextOffscreen.getImageData(0, 0, this.offscreenWidth, this.offscreenHeight);
5033 var index = this.offscreenRGBCount;
5035 this.canvasBuffer.data[index -= 4] = 0xF8;
5036 this.canvasBuffer.data[index + 1] = 0xF8;
5037 this.canvasBuffer.data[index + 2] = 0xF8;
5038 this.canvasBuffer.data[index + 3] = 0xFF;
5040 this.graphicsBlit();
5041 this.canvas.style.visibility = "visible";
5042 if (this.swizzledFrame == null) {
5043 this.swizzledFrame = this.getTypedArray(69120, 0xFF, "uint8");
5045 //Test the draw system and browser vblank latching:
5046 this.drewFrame = true; //Copy the latest graphics to buffer.
5050 throw(new Error("HTML5 Canvas support required: " + error.message + "file: " + error.fileName + ", line: " + error.lineNumber));
5053 GameBoyCore.prototype.graphicsBlit = function () {
5054 if (this.offscreenWidth == this.onscreenWidth && this.offscreenHeight == this.onscreenHeight) {
5055 this.drawContextOnscreen.putImageData(this.canvasBuffer, 0, 0);
5058 this.drawContextOffscreen.putImageData(this.canvasBuffer, 0, 0);
5059 this.drawContextOnscreen.drawImage(this.canvasOffscreen, 0, 0, this.onscreenWidth, this.onscreenHeight);
5062 GameBoyCore.prototype.JoyPadEvent = function (key, down) {
5064 this.JoyPad &= 0xFF ^ (1 << key);
5065 if (!this.cGBC && (!this.usedBootROM || !this.usedGBCBootROM)) {
5066 this.interruptsRequested |= 0x10; //A real GBC doesn't set this!
5067 this.remainingClocks = 0;
5068 this.checkIRQMatching();
5072 this.JoyPad |= (1 << key);
5074 this.memory[0xFF00] = (this.memory[0xFF00] & 0x30) + ((((this.memory[0xFF00] & 0x20) == 0) ? (this.JoyPad >> 4) : 0xF) & (((this.memory[0xFF00] & 0x10) == 0) ? (this.JoyPad & 0xF) : 0xF));
5075 this.CPUStopped = false;
5077 GameBoyCore.prototype.GyroEvent = function (x, y) {
5080 this.highX = x >> 8;
5081 this.lowX = x & 0xFF;
5084 this.highY = y >> 8;
5085 this.lowY = y & 0xFF;
5087 GameBoyCore.prototype.initSound = function () {
5088 this.sampleSize = 0x400000 / 1000 * settings[6];
5089 this.machineOut = settings[13];
5092 var parentObj = this;
5093 this.audioHandle = new XAudioServer(2, 0x400000 / settings[13], 0, Math.max(this.sampleSize * settings[8] / settings[13], 8192) << 1, null, settings[14]);
5094 this.initAudioBuffer();
5097 cout("Audio system cannot run: " + error.message, 2);
5098 settings[0] = false;
5101 else if (this.audioHandle) {
5102 //Mute the audio output, as it has an immediate silencing effect:
5104 this.audioHandle.changeVolume(0);
5109 GameBoyCore.prototype.changeVolume = function () {
5110 if (settings[0] && this.audioHandle) {
5112 this.audioHandle.changeVolume(settings[14]);
5117 GameBoyCore.prototype.initAudioBuffer = function () {
5118 this.audioIndex = 0;
5119 this.bufferContainAmount = Math.max(this.sampleSize * settings[7] / settings[13], 4096) << 1;
5120 this.numSamplesTotal = (this.sampleSize - (this.sampleSize % settings[13])) | 0;
5121 this.currentBuffer = this.getTypedArray(this.numSamplesTotal, 0xF0F0, "int32");
5122 this.secondaryBuffer = this.getTypedArray((this.numSamplesTotal << 1) / settings[13], 0, "float32");
5124 GameBoyCore.prototype.intializeWhiteNoise = function () {
5125 //Noise Sample Tables:
5126 var randomFactor = 1;
5127 //15-bit LSFR Cache Generation:
5128 this.LSFR15Table = this.getTypedArray(0x80000, 0, "int8");
5129 var LSFR = 0x7FFF; //Seed value has all its bits set.
5130 var LSFRShifted = 0x3FFF;
5131 for (var index = 0; index < 0x8000; ++index) {
5132 //Normalize the last LSFR value for usage:
5133 randomFactor = 1 - (LSFR & 1); //Docs say it's the inverse.
5134 //Cache the different volume level results:
5135 this.LSFR15Table[0x08000 | index] = randomFactor;
5136 this.LSFR15Table[0x10000 | index] = randomFactor * 0x2;
5137 this.LSFR15Table[0x18000 | index] = randomFactor * 0x3;
5138 this.LSFR15Table[0x20000 | index] = randomFactor * 0x4;
5139 this.LSFR15Table[0x28000 | index] = randomFactor * 0x5;
5140 this.LSFR15Table[0x30000 | index] = randomFactor * 0x6;
5141 this.LSFR15Table[0x38000 | index] = randomFactor * 0x7;
5142 this.LSFR15Table[0x40000 | index] = randomFactor * 0x8;
5143 this.LSFR15Table[0x48000 | index] = randomFactor * 0x9;
5144 this.LSFR15Table[0x50000 | index] = randomFactor * 0xA;
5145 this.LSFR15Table[0x58000 | index] = randomFactor * 0xB;
5146 this.LSFR15Table[0x60000 | index] = randomFactor * 0xC;
5147 this.LSFR15Table[0x68000 | index] = randomFactor * 0xD;
5148 this.LSFR15Table[0x70000 | index] = randomFactor * 0xE;
5149 this.LSFR15Table[0x78000 | index] = randomFactor * 0xF;
5150 //Recompute the LSFR algorithm:
5151 LSFRShifted = LSFR >> 1;
5152 LSFR = LSFRShifted | (((LSFRShifted ^ LSFR) & 0x1) << 14);
5154 //7-bit LSFR Cache Generation:
5155 this.LSFR7Table = this.getTypedArray(0x800, 0, "int8");
5156 LSFR = 0x7F; //Seed value has all its bits set.
5157 for (index = 0; index < 0x80; ++index) {
5158 //Normalize the last LSFR value for usage:
5159 randomFactor = 1 - (LSFR & 1); //Docs say it's the inverse.
5160 //Cache the different volume level results:
5161 this.LSFR7Table[0x080 | index] = randomFactor;
5162 this.LSFR7Table[0x100 | index] = randomFactor * 0x2;
5163 this.LSFR7Table[0x180 | index] = randomFactor * 0x3;
5164 this.LSFR7Table[0x200 | index] = randomFactor * 0x4;
5165 this.LSFR7Table[0x280 | index] = randomFactor * 0x5;
5166 this.LSFR7Table[0x300 | index] = randomFactor * 0x6;
5167 this.LSFR7Table[0x380 | index] = randomFactor * 0x7;
5168 this.LSFR7Table[0x400 | index] = randomFactor * 0x8;
5169 this.LSFR7Table[0x480 | index] = randomFactor * 0x9;
5170 this.LSFR7Table[0x500 | index] = randomFactor * 0xA;
5171 this.LSFR7Table[0x580 | index] = randomFactor * 0xB;
5172 this.LSFR7Table[0x600 | index] = randomFactor * 0xC;
5173 this.LSFR7Table[0x680 | index] = randomFactor * 0xD;
5174 this.LSFR7Table[0x700 | index] = randomFactor * 0xE;
5175 this.LSFR7Table[0x780 | index] = randomFactor * 0xF;
5176 //Recompute the LSFR algorithm:
5177 LSFRShifted = LSFR >> 1;
5178 LSFR = LSFRShifted | (((LSFRShifted ^ LSFR) & 0x1) << 6);
5180 if (!this.noiseSampleTable && this.memory.length == 0x10000) {
5181 //If enabling audio for the first time after a game is already running, set up the internal table reference:
5182 this.noiseSampleTable = ((this.memory[0xFF22] & 0x8) == 0x8) ? this.LSFR7Table : this.LSFR15Table;
5185 GameBoyCore.prototype.audioUnderrunAdjustment = function () {
5187 var underrunAmount = this.bufferContainAmount - this.audioHandle.remainingBuffer();
5188 if (underrunAmount > 0) {
5189 this.CPUCyclesTotalCurrent += (underrunAmount >> 1) * this.machineOut;
5190 this.recalculateIterationClockLimit();
5194 GameBoyCore.prototype.initializeAudioStartState = function () {
5195 this.channel1FrequencyTracker = 0x2000;
5196 this.channel1DutyTracker = 0;
5197 this.channel1CachedDuty = this.dutyLookup[2];
5198 this.channel1totalLength = 0;
5199 this.channel1envelopeVolume = 0;
5200 this.channel1envelopeType = false;
5201 this.channel1envelopeSweeps = 0;
5202 this.channel1envelopeSweepsLast = 0;
5203 this.channel1consecutive = true;
5204 this.channel1frequency = 0;
5205 this.channel1SweepFault = false;
5206 this.channel1ShadowFrequency = 0;
5207 this.channel1timeSweep = 1;
5208 this.channel1lastTimeSweep = 0;
5209 this.channel1numSweep = 0;
5210 this.channel1frequencySweepDivider = 0;
5211 this.channel1decreaseSweep = false;
5212 this.channel2FrequencyTracker = 0x2000;
5213 this.channel2DutyTracker = 0;
5214 this.channel2CachedDuty = this.dutyLookup[2];
5215 this.channel2totalLength = 0;
5216 this.channel2envelopeVolume = 0;
5217 this.channel2envelopeType = false;
5218 this.channel2envelopeSweeps = 0;
5219 this.channel2envelopeSweepsLast = 0;
5220 this.channel2consecutive = true;
5221 this.channel2frequency = 0;
5222 this.channel3canPlay = false;
5223 this.channel3totalLength = 0;
5224 this.channel3patternType = 4;
5225 this.channel3frequency = 0;
5226 this.channel3consecutive = true;
5227 this.channel3Counter = 0x800;
5228 this.channel4FrequencyPeriod = 8;
5229 this.channel4totalLength = 0;
5230 this.channel4envelopeVolume = 0;
5231 this.channel4currentVolume = 0;
5232 this.channel4envelopeType = false;
5233 this.channel4envelopeSweeps = 0;
5234 this.channel4envelopeSweepsLast = 0;
5235 this.channel4consecutive = true;
5236 this.channel4BitRange = 0x7FFF;
5237 this.noiseSampleTable = this.LSFR15Table;
5238 this.channel4VolumeShifter = 15;
5239 this.channel1FrequencyCounter = 0x2000;
5240 this.channel2FrequencyCounter = 0x2000;
5241 this.channel3Counter = 0x800;
5242 this.channel3FrequencyPeriod = 0x800;
5243 this.channel3lastSampleLookup = 0;
5244 this.channel4lastSampleLookup = 0;
5245 this.VinLeftChannelMasterVolume = 8;
5246 this.VinRightChannelMasterVolume = 8;
5247 this.mixerOutputCache = 0;
5248 this.sequencerClocks = 0x2000;
5249 this.sequencePosition = 0;
5250 this.channel4FrequencyPeriod = 8;
5251 this.channel4Counter = 8;
5252 this.cachedChannel3Sample = 0;
5253 this.cachedChannel4Sample = 0;
5254 this.channel1Enabled = false;
5255 this.channel2Enabled = false;
5256 this.channel3Enabled = false;
5257 this.channel4Enabled = false;
5258 this.channel1canPlay = false;
5259 this.channel2canPlay = false;
5260 this.channel4canPlay = false;
5261 this.channel1OutputLevelCache();
5262 this.channel2OutputLevelCache();
5263 this.channel3OutputLevelCache();
5264 this.channel4OutputLevelCache();
5266 GameBoyCore.prototype.outputAudio = function () {
5267 var sampleFactor = 0;
5268 var dirtySample = 0;
5271 var destinationPosition = 0;
5272 var divisor1 = settings[13];
5273 var divisor2 = divisor1 * 0xF0;
5274 for (var sourcePosition = 0; sourcePosition < this.numSamplesTotal;) {
5275 for (sampleFactor = averageL = averageR = 0; sampleFactor < divisor1; ++sampleFactor) {
5276 dirtySample = this.currentBuffer[sourcePosition++];
5277 averageL += dirtySample >> 9;
5278 averageR += dirtySample & 0x1FF;
5280 this.secondaryBuffer[destinationPosition++] = averageL / divisor2 - 1;
5281 this.secondaryBuffer[destinationPosition++] = averageR / divisor2 - 1;
5283 this.audioHandle.writeAudioNoCallback(this.secondaryBuffer);
5285 //Below are the audio generation functions timed against the CPU:
5286 GameBoyCore.prototype.generateAudio = function (numSamples) {
5287 if (this.soundMasterEnabled && !this.CPUStopped) {
5288 for (var samplesToGenerate = 0; numSamples > 0;) {
5289 samplesToGenerate = (numSamples < this.sequencerClocks) ? numSamples : this.sequencerClocks;
5290 this.sequencerClocks -= samplesToGenerate;
5291 numSamples -= samplesToGenerate;
5292 while (--samplesToGenerate > -1) {
5293 this.computeAudioChannels();
5294 this.currentBuffer[this.audioIndex++] = this.mixerOutputCache;
5295 if (this.audioIndex == this.numSamplesTotal) {
5296 this.audioIndex = 0;
5300 if (this.sequencerClocks == 0) {
5301 this.audioComputeSequencer();
5302 this.sequencerClocks = 0x2000;
5308 while (--numSamples > -1) {
5309 this.currentBuffer[this.audioIndex++] = 0xF0F0;
5310 if (this.audioIndex == this.numSamplesTotal) {
5311 this.audioIndex = 0;
5317 //Generate audio, but don't actually output it (Used for when sound is disabled by user/browser):
5318 GameBoyCore.prototype.generateAudioFake = function (numSamples) {
5319 if (this.soundMasterEnabled && !this.CPUStopped) {
5320 while (--numSamples > -1) {
5321 this.computeAudioChannels();
5322 if (--this.sequencerClocks == 0) {
5323 this.audioComputeSequencer();
5324 this.sequencerClocks = 0x2000;
5329 GameBoyCore.prototype.audioJIT = function () {
5330 //Audio Sample Generation Timing:
5332 this.generateAudio(this.audioTicks);
5335 this.generateAudioFake(this.audioTicks);
5337 this.audioTicks = 0;
5339 GameBoyCore.prototype.audioComputeSequencer = function () {
5340 switch (this.sequencePosition++) {
5342 this.clockAudioLength();
5345 this.clockAudioLength();
5346 this.clockAudioSweep();
5349 this.clockAudioLength();
5352 this.clockAudioLength();
5353 this.clockAudioSweep();
5356 this.clockAudioEnvelope();
5357 this.sequencePosition = 0;
5360 GameBoyCore.prototype.clockAudioLength = function () {
5362 if (this.channel1totalLength > 1) {
5363 --this.channel1totalLength;
5365 else if (this.channel1totalLength == 1) {
5366 this.channel1totalLength = 0;
5367 this.channel1EnableCheck();
5368 this.memory[0xFF26] &= 0xFE; //Channel #1 On Flag Off
5371 if (this.channel2totalLength > 1) {
5372 --this.channel2totalLength;
5374 else if (this.channel2totalLength == 1) {
5375 this.channel2totalLength = 0;
5376 this.channel2EnableCheck();
5377 this.memory[0xFF26] &= 0xFD; //Channel #2 On Flag Off
5380 if (this.channel3totalLength > 1) {
5381 --this.channel3totalLength;
5383 else if (this.channel3totalLength == 1) {
5384 this.channel3totalLength = 0;
5385 this.channel3EnableCheck();
5386 this.memory[0xFF26] &= 0xFB; //Channel #3 On Flag Off
5389 if (this.channel4totalLength > 1) {
5390 --this.channel4totalLength;
5392 else if (this.channel4totalLength == 1) {
5393 this.channel4totalLength = 0;
5394 this.channel4EnableCheck();
5395 this.memory[0xFF26] &= 0xF7; //Channel #4 On Flag Off
5398 GameBoyCore.prototype.clockAudioSweep = function () {
5400 if (!this.channel1SweepFault && this.channel1timeSweep > 0) {
5401 if (--this.channel1timeSweep == 0) {
5402 this.runAudioSweep();
5406 GameBoyCore.prototype.runAudioSweep = function () {
5408 if (this.channel1lastTimeSweep > 0) {
5409 if (this.channel1frequencySweepDivider > 0) {
5410 if (this.channel1numSweep > 0) {
5411 --this.channel1numSweep;
5412 if (this.channel1decreaseSweep) {
5413 this.channel1ShadowFrequency -= this.channel1ShadowFrequency >> this.channel1frequencySweepDivider;
5414 this.channel1frequency = this.channel1ShadowFrequency & 0x7FF;
5415 this.channel1FrequencyTracker = (0x800 - this.channel1frequency) << 2;
5418 this.channel1ShadowFrequency += this.channel1ShadowFrequency >> this.channel1frequencySweepDivider;
5419 this.channel1frequency = this.channel1ShadowFrequency;
5420 if (this.channel1ShadowFrequency <= 0x7FF) {
5421 this.channel1FrequencyTracker = (0x800 - this.channel1frequency) << 2;
5422 //Run overflow check twice:
5423 if ((this.channel1ShadowFrequency + (this.channel1ShadowFrequency >> this.channel1frequencySweepDivider)) > 0x7FF) {
5424 this.channel1SweepFault = true;
5425 this.channel1EnableCheck();
5426 this.memory[0xFF26] &= 0xFE; //Channel #1 On Flag Off
5430 this.channel1frequency &= 0x7FF;
5431 this.channel1SweepFault = true;
5432 this.channel1EnableCheck();
5433 this.memory[0xFF26] &= 0xFE; //Channel #1 On Flag Off
5437 this.channel1timeSweep = this.channel1lastTimeSweep;
5440 //Channel has sweep disabled and timer becomes a length counter:
5441 this.channel1SweepFault = true;
5442 this.channel1EnableCheck();
5446 GameBoyCore.prototype.clockAudioEnvelope = function () {
5448 if (this.channel1envelopeSweepsLast > -1) {
5449 if (this.channel1envelopeSweeps > 0) {
5450 --this.channel1envelopeSweeps;
5453 if (!this.channel1envelopeType) {
5454 if (this.channel1envelopeVolume > 0) {
5455 --this.channel1envelopeVolume;
5456 this.channel1envelopeSweeps = this.channel1envelopeSweepsLast;
5457 this.channel1OutputLevelCache();
5460 this.channel1envelopeSweepsLast = -1;
5463 else if (this.channel1envelopeVolume < 0xF) {
5464 ++this.channel1envelopeVolume;
5465 this.channel1envelopeSweeps = this.channel1envelopeSweepsLast;
5466 this.channel1OutputLevelCache();
5469 this.channel1envelopeSweepsLast = -1;
5474 if (this.channel2envelopeSweepsLast > -1) {
5475 if (this.channel2envelopeSweeps > 0) {
5476 --this.channel2envelopeSweeps;
5479 if (!this.channel2envelopeType) {
5480 if (this.channel2envelopeVolume > 0) {
5481 --this.channel2envelopeVolume;
5482 this.channel2envelopeSweeps = this.channel2envelopeSweepsLast;
5483 this.channel2OutputLevelCache();
5486 this.channel2envelopeSweepsLast = -1;
5489 else if (this.channel2envelopeVolume < 0xF) {
5490 ++this.channel2envelopeVolume;
5491 this.channel2envelopeSweeps = this.channel2envelopeSweepsLast;
5492 this.channel2OutputLevelCache();
5495 this.channel2envelopeSweepsLast = -1;
5500 if (this.channel4envelopeSweepsLast > -1) {
5501 if (this.channel4envelopeSweeps > 0) {
5502 --this.channel4envelopeSweeps;
5505 if (!this.channel4envelopeType) {
5506 if (this.channel4envelopeVolume > 0) {
5507 this.channel4currentVolume = --this.channel4envelopeVolume << this.channel4VolumeShifter;
5508 this.channel4envelopeSweeps = this.channel4envelopeSweepsLast;
5509 this.channel4UpdateCache();
5512 this.channel4envelopeSweepsLast = -1;
5515 else if (this.channel4envelopeVolume < 0xF) {
5516 this.channel4currentVolume = ++this.channel4envelopeVolume << this.channel4VolumeShifter;
5517 this.channel4envelopeSweeps = this.channel4envelopeSweepsLast;
5518 this.channel4UpdateCache();
5521 this.channel4envelopeSweepsLast = -1;
5526 GameBoyCore.prototype.computeAudioChannels = function () {
5527 //Channel 1 counter:
5528 if (--this.channel1FrequencyCounter == 0) {
5529 this.channel1FrequencyCounter = this.channel1FrequencyTracker;
5530 this.channel1DutyTracker = (this.channel1DutyTracker + 1) & 0x7;
5531 this.channel1OutputLevelTrimaryCache();
5533 //Channel 2 counter:
5534 if (--this.channel2FrequencyCounter == 0) {
5535 this.channel2FrequencyCounter = this.channel2FrequencyTracker;
5536 this.channel2DutyTracker = (this.channel2DutyTracker + 1) & 0x7;
5537 this.channel2OutputLevelTrimaryCache();
5539 //Channel 3 counter:
5540 if (--this.channel3Counter == 0) {
5541 if (this.channel3canPlay) {
5542 this.channel3lastSampleLookup = (this.channel3lastSampleLookup + 1) & 0x1F;
5544 this.channel3Counter = this.channel3FrequencyPeriod;
5545 this.channel3UpdateCache();
5547 //Channel 4 counter:
5548 if (--this.channel4Counter == 0) {
5549 this.channel4lastSampleLookup = (this.channel4lastSampleLookup + 1) & this.channel4BitRange;
5550 this.channel4Counter = this.channel4FrequencyPeriod;
5551 this.channel4UpdateCache();
5554 GameBoyCore.prototype.channel1EnableCheck = function () {
5555 this.channel1Enabled = ((this.channel1consecutive || this.channel1totalLength > 0) && !this.channel1SweepFault && this.channel1canPlay);
5556 this.channel1OutputLevelSecondaryCache();
5558 GameBoyCore.prototype.channel1VolumeEnableCheck = function () {
5559 this.channel1canPlay = (this.memory[0xFF12] > 7);
5560 this.channel1EnableCheck();
5561 this.channel1OutputLevelSecondaryCache();
5563 GameBoyCore.prototype.channel1OutputLevelCache = function () {
5564 this.channel1currentSampleLeft = (this.leftChannel1) ? this.channel1envelopeVolume : 0;
5565 this.channel1currentSampleRight = (this.rightChannel1) ? this.channel1envelopeVolume : 0;
5566 this.channel1OutputLevelSecondaryCache();
5568 GameBoyCore.prototype.channel1OutputLevelSecondaryCache = function () {
5569 if (this.channel1Enabled) {
5570 this.channel1currentSampleLeftSecondary = this.channel1currentSampleLeft;
5571 this.channel1currentSampleRightSecondary = this.channel1currentSampleRight;
5574 this.channel1currentSampleLeftSecondary = 0;
5575 this.channel1currentSampleRightSecondary = 0;
5577 this.channel1OutputLevelTrimaryCache();
5579 GameBoyCore.prototype.channel1OutputLevelTrimaryCache = function () {
5580 if (this.channel1CachedDuty[this.channel1DutyTracker]) {
5581 this.channel1currentSampleLeftTrimary = this.channel1currentSampleLeftSecondary;
5582 this.channel1currentSampleRightTrimary = this.channel1currentSampleRightSecondary;
5585 this.channel1currentSampleLeftTrimary = 0;
5586 this.channel1currentSampleRightTrimary = 0;
5588 this.mixerOutputLevelCache();
5590 GameBoyCore.prototype.channel2EnableCheck = function () {
5591 this.channel2Enabled = ((this.channel2consecutive || this.channel2totalLength > 0) && this.channel2canPlay);
5592 this.channel2OutputLevelSecondaryCache();
5594 GameBoyCore.prototype.channel2VolumeEnableCheck = function () {
5595 this.channel2canPlay = (this.memory[0xFF17] > 7);
5596 this.channel2EnableCheck();
5597 this.channel2OutputLevelSecondaryCache();
5599 GameBoyCore.prototype.channel2OutputLevelCache = function () {
5600 this.channel2currentSampleLeft = (this.leftChannel2) ? this.channel2envelopeVolume : 0;
5601 this.channel2currentSampleRight = (this.rightChannel2) ? this.channel2envelopeVolume : 0;
5602 this.channel2OutputLevelSecondaryCache();
5604 GameBoyCore.prototype.channel2OutputLevelSecondaryCache = function () {
5605 if (this.channel2Enabled) {
5606 this.channel2currentSampleLeftSecondary = this.channel2currentSampleLeft;
5607 this.channel2currentSampleRightSecondary = this.channel2currentSampleRight;
5610 this.channel2currentSampleLeftSecondary = 0;
5611 this.channel2currentSampleRightSecondary = 0;
5613 this.channel2OutputLevelTrimaryCache();
5615 GameBoyCore.prototype.channel2OutputLevelTrimaryCache = function () {
5616 if (this.channel2CachedDuty[this.channel2DutyTracker]) {
5617 this.channel2currentSampleLeftTrimary = this.channel2currentSampleLeftSecondary;
5618 this.channel2currentSampleRightTrimary = this.channel2currentSampleRightSecondary;
5621 this.channel2currentSampleLeftTrimary = 0;
5622 this.channel2currentSampleRightTrimary = 0;
5624 this.mixerOutputLevelCache();
5626 GameBoyCore.prototype.channel3EnableCheck = function () {
5627 this.channel3Enabled = (/*this.channel3canPlay && */(this.channel3consecutive || this.channel3totalLength > 0));
5628 this.channel3OutputLevelSecondaryCache();
5630 GameBoyCore.prototype.channel3OutputLevelCache = function () {
5631 this.channel3currentSampleLeft = (this.leftChannel3) ? this.cachedChannel3Sample : 0;
5632 this.channel3currentSampleRight = (this.rightChannel3) ? this.cachedChannel3Sample : 0;
5633 this.channel3OutputLevelSecondaryCache();
5635 GameBoyCore.prototype.channel3OutputLevelSecondaryCache = function () {
5636 if (this.channel3Enabled) {
5637 this.channel3currentSampleLeftSecondary = this.channel3currentSampleLeft;
5638 this.channel3currentSampleRightSecondary = this.channel3currentSampleRight;
5641 this.channel3currentSampleLeftSecondary = 0;
5642 this.channel3currentSampleRightSecondary = 0;
5644 this.mixerOutputLevelCache();
5646 GameBoyCore.prototype.channel4EnableCheck = function () {
5647 this.channel4Enabled = ((this.channel4consecutive || this.channel4totalLength > 0) && this.channel4canPlay);
5648 this.channel4OutputLevelSecondaryCache();
5650 GameBoyCore.prototype.channel4VolumeEnableCheck = function () {
5651 this.channel4canPlay = (this.memory[0xFF21] > 7);
5652 this.channel4EnableCheck();
5653 this.channel4OutputLevelSecondaryCache();
5655 GameBoyCore.prototype.channel4OutputLevelCache = function () {
5656 this.channel4currentSampleLeft = (this.leftChannel4) ? this.cachedChannel4Sample : 0;
5657 this.channel4currentSampleRight = (this.rightChannel4) ? this.cachedChannel4Sample : 0;
5658 this.channel4OutputLevelSecondaryCache();
5660 GameBoyCore.prototype.channel4OutputLevelSecondaryCache = function () {
5661 if (this.channel4Enabled) {
5662 this.channel4currentSampleLeftSecondary = this.channel4currentSampleLeft;
5663 this.channel4currentSampleRightSecondary = this.channel4currentSampleRight;
5666 this.channel4currentSampleLeftSecondary = 0;
5667 this.channel4currentSampleRightSecondary = 0;
5669 this.mixerOutputLevelCache();
5671 GameBoyCore.prototype.mixerOutputLevelCache = function () {
5672 this.mixerOutputCache = ((((this.channel1currentSampleLeftTrimary + this.channel2currentSampleLeftTrimary + this.channel3currentSampleLeftSecondary + this.channel4currentSampleLeftSecondary) * this.VinLeftChannelMasterVolume) << 9) +
5673 ((this.channel1currentSampleRightTrimary + this.channel2currentSampleRightTrimary + this.channel3currentSampleRightSecondary + this.channel4currentSampleRightSecondary) * this.VinRightChannelMasterVolume));
5675 GameBoyCore.prototype.channel3UpdateCache = function () {
5676 this.cachedChannel3Sample = this.channel3PCM[this.channel3lastSampleLookup] >> this.channel3patternType;
5677 this.channel3OutputLevelCache();
5679 GameBoyCore.prototype.channel3WriteRAM = function (address, data) {
5680 if (this.channel3canPlay) {
5682 //address = this.channel3lastSampleLookup >> 1;
5684 this.memory[0xFF30 | address] = data;
5686 this.channel3PCM[address] = data >> 4;
5687 this.channel3PCM[address | 1] = data & 0xF;
5689 GameBoyCore.prototype.channel4UpdateCache = function () {
5690 this.cachedChannel4Sample = this.noiseSampleTable[this.channel4currentVolume | this.channel4lastSampleLookup];
5691 this.channel4OutputLevelCache();
5693 GameBoyCore.prototype.run = function () {
5694 //The preprocessing before the actual iteration loop:
5695 if ((this.stopEmulator & 2) == 0) {
5696 if ((this.stopEmulator & 1) == 1) {
5697 if (!this.CPUStopped) {
5698 this.stopEmulator = 0;
5699 this.drewFrame = false;
5700 this.audioUnderrunAdjustment();
5701 this.clockUpdate(); //RTC clocking.
5703 this.executeIteration();
5705 else { //Finish the HALT rundown execution.
5707 this.calculateHALTPeriod();
5709 this.updateCoreFull();
5712 this.executeIteration();
5715 //Request the graphics target to be updated:
5719 this.audioUnderrunAdjustment();
5720 this.audioTicks += this.CPUCyclesTotal;
5722 this.stopEmulator |= 1; //End current loop.
5725 else { //We can only get here if there was an internal error, but the loop was restarted.
5726 cout("Iterator restarted a faulted core.", 2);
5732 GameBoyCore.prototype.executeIteration = function () {
5733 //Iterate the interpreter loop:
5734 var opcodeToExecute = 0;
5736 while (this.stopEmulator == 0) {
5738 switch (this.IRQEnableDelay) {
5741 this.checkIRQMatching();
5743 --this.IRQEnableDelay;
5745 //Is an IRQ set to fire?:
5746 if (this.IRQLineMatched > 0) {
5747 //IME is true and and interrupt was matched:
5750 //Fetch the current opcode:
5751 opcodeToExecute = this.memoryReader[this.programCounter](this, this.programCounter);
5752 //Increment the program counter to the next instruction:
5753 this.programCounter = (this.programCounter + 1) & 0xFFFF;
5754 //Check for the program counter quirk:
5755 if (this.skipPCIncrement) {
5756 this.programCounter = (this.programCounter - 1) & 0xFFFF;
5757 this.skipPCIncrement = false;
5759 //Get how many CPU cycles the current instruction counts for:
5760 this.CPUTicks = this.TICKTable[opcodeToExecute];
5761 //Execute the current instruction:
5762 this.OPCODE[opcodeToExecute](this);
5763 //Update the state (Inlined updateCoreFull manually here):
5764 //Update the clocking for the LCD emulation:
5765 this.LCDTicks += this.CPUTicks >> this.doubleSpeedShifter; //LCD Timing
5766 this.LCDCONTROL[this.actualScanLine](this); //Scan Line and STAT Mode Control
5767 //Single-speed relative timing for A/V emulation:
5768 timedTicks = this.CPUTicks >> this.doubleSpeedShifter; //CPU clocking can be updated from the LCD handling.
5769 this.audioTicks += timedTicks; //Audio Timing
5770 this.emulatorTicks += timedTicks; //Emulator Timing
5772 this.DIVTicks += this.CPUTicks; //DIV Timing
5773 if (this.TIMAEnabled) { //TIMA Timing
5774 this.timerTicks += this.CPUTicks;
5775 while (this.timerTicks >= this.TACClocker) {
5776 this.timerTicks -= this.TACClocker;
5777 if (++this.memory[0xFF05] == 0x100) {
5778 this.memory[0xFF05] = this.memory[0xFF06];
5779 this.interruptsRequested |= 0x4;
5780 this.checkIRQMatching();
5784 if (this.serialTimer > 0) { //Serial Timing
5786 this.serialTimer -= this.CPUTicks;
5787 if (this.serialTimer <= 0) {
5788 this.interruptsRequested |= 0x8;
5789 this.checkIRQMatching();
5792 this.serialShiftTimer -= this.CPUTicks;
5793 if (this.serialShiftTimer <= 0) {
5794 this.serialShiftTimer = this.serialShiftTimerAllocated;
5795 this.memory[0xFF01] = ((this.memory[0xFF01] << 1) & 0xFE) | 0x01; //We could shift in actual link data here if we were to implement such!!!
5798 //End of iteration routine:
5799 if (this.emulatorTicks >= this.CPUCyclesTotal) {
5800 this.iterationEndRoutine();
5802 // Start of code added for benchmarking:
5803 this.instructions += 1;
5804 if (this.instructions > this.totalInstructions) {
5805 this.iterationEndRoutine();
5806 this.stopEmulator |= 2;
5809 // End of code added for benchmarking.
5812 GameBoyCore.prototype.iterationEndRoutine = function () {
5813 if ((this.stopEmulator & 0x1) == 0) {
5814 this.audioJIT(); //Make sure we at least output once per iteration.
5815 //Update DIV Alignment (Integer overflow safety):
5816 this.memory[0xFF04] = (this.memory[0xFF04] + (this.DIVTicks >> 8)) & 0xFF;
5817 this.DIVTicks &= 0xFF;
5818 //Update emulator flags:
5819 this.stopEmulator |= 1; //End current loop.
5820 this.emulatorTicks -= this.CPUCyclesTotal;
5821 this.CPUCyclesTotalCurrent += this.CPUCyclesTotalRoundoff;
5822 this.recalculateIterationClockLimit();
5825 GameBoyCore.prototype.handleSTOP = function () {
5826 this.CPUStopped = true; //Stop CPU until joypad input changes.
5827 this.iterationEndRoutine();
5828 if (this.emulatorTicks < 0) {
5829 this.audioTicks -= this.emulatorTicks;
5833 GameBoyCore.prototype.recalculateIterationClockLimit = function () {
5834 var endModulus = this.CPUCyclesTotalCurrent % 4;
5835 this.CPUCyclesTotal = this.CPUCyclesTotalBase + this.CPUCyclesTotalCurrent - endModulus;
5836 this.CPUCyclesTotalCurrent = endModulus;
5838 GameBoyCore.prototype.scanLineMode2 = function () { //OAM Search Period
5839 if (this.STATTracker != 1) {
5840 if (this.mode2TriggerSTAT) {
5841 this.interruptsRequested |= 0x2;
5842 this.checkIRQMatching();
5844 this.STATTracker = 1;
5848 GameBoyCore.prototype.scanLineMode3 = function () { //Scan Line Drawing Period
5849 if (this.modeSTAT != 3) {
5850 if (this.STATTracker == 0 && this.mode2TriggerSTAT) {
5851 this.interruptsRequested |= 0x2;
5852 this.checkIRQMatching();
5854 this.STATTracker = 1;
5858 GameBoyCore.prototype.scanLineMode0 = function () { //Horizontal Blanking Period
5859 if (this.modeSTAT != 0) {
5860 if (this.STATTracker != 2) {
5861 if (this.STATTracker == 0) {
5862 if (this.mode2TriggerSTAT) {
5863 this.interruptsRequested |= 0x2;
5864 this.checkIRQMatching();
5868 this.incrementScanLineQueue();
5869 this.updateSpriteCount(this.actualScanLine);
5870 this.STATTracker = 2;
5872 if (this.LCDTicks >= this.spriteCount) {
5873 if (this.hdmaRunning) {
5876 if (this.mode0TriggerSTAT) {
5877 this.interruptsRequested |= 0x2;
5878 this.checkIRQMatching();
5880 this.STATTracker = 3;
5885 GameBoyCore.prototype.clocksUntilLYCMatch = function () {
5886 if (this.memory[0xFF45] != 0) {
5887 if (this.memory[0xFF45] > this.actualScanLine) {
5888 return 456 * (this.memory[0xFF45] - this.actualScanLine);
5890 return 456 * (154 - this.actualScanLine + this.memory[0xFF45]);
5892 return (456 * ((this.actualScanLine == 153 && this.memory[0xFF44] == 0) ? 154 : (153 - this.actualScanLine))) + 8;
5894 GameBoyCore.prototype.clocksUntilMode0 = function () {
5895 switch (this.modeSTAT) {
5897 if (this.actualScanLine == 143) {
5898 this.updateSpriteCount(0);
5899 return this.spriteCount + 5016;
5901 this.updateSpriteCount(this.actualScanLine + 1);
5902 return this.spriteCount + 456;
5905 this.updateSpriteCount(this.actualScanLine);
5906 return this.spriteCount;
5908 this.updateSpriteCount(0);
5909 return this.spriteCount + (456 * (154 - this.actualScanLine));
5912 GameBoyCore.prototype.updateSpriteCount = function (line) {
5913 this.spriteCount = 252;
5914 if (this.cGBC && this.gfxSpriteShow) { //Is the window enabled and are we in CGB mode?
5915 var lineAdjusted = line + 0x10;
5917 var yCap = (this.gfxSpriteNormalHeight) ? 0x8 : 0x10;
5918 for (var OAMAddress = 0xFE00; OAMAddress < 0xFEA0 && this.spriteCount < 312; OAMAddress += 4) {
5919 yoffset = lineAdjusted - this.memory[OAMAddress];
5920 if (yoffset > -1 && yoffset < yCap) {
5921 this.spriteCount += 6;
5926 GameBoyCore.prototype.matchLYC = function () { //LYC Register Compare
5927 if (this.memory[0xFF44] == this.memory[0xFF45]) {
5928 this.memory[0xFF41] |= 0x04;
5929 if (this.LYCMatchTriggerSTAT) {
5930 this.interruptsRequested |= 0x2;
5931 this.checkIRQMatching();
5935 this.memory[0xFF41] &= 0x7B;
5938 GameBoyCore.prototype.updateCore = function () {
5939 //Update the clocking for the LCD emulation:
5940 this.LCDTicks += this.CPUTicks >> this.doubleSpeedShifter; //LCD Timing
5941 this.LCDCONTROL[this.actualScanLine](this); //Scan Line and STAT Mode Control
5942 //Single-speed relative timing for A/V emulation:
5943 var timedTicks = this.CPUTicks >> this.doubleSpeedShifter; //CPU clocking can be updated from the LCD handling.
5944 this.audioTicks += timedTicks; //Audio Timing
5945 this.emulatorTicks += timedTicks; //Emulator Timing
5947 this.DIVTicks += this.CPUTicks; //DIV Timing
5948 if (this.TIMAEnabled) { //TIMA Timing
5949 this.timerTicks += this.CPUTicks;
5950 while (this.timerTicks >= this.TACClocker) {
5951 this.timerTicks -= this.TACClocker;
5952 if (++this.memory[0xFF05] == 0x100) {
5953 this.memory[0xFF05] = this.memory[0xFF06];
5954 this.interruptsRequested |= 0x4;
5955 this.checkIRQMatching();
5959 if (this.serialTimer > 0) { //Serial Timing
5961 this.serialTimer -= this.CPUTicks;
5962 if (this.serialTimer <= 0) {
5963 this.interruptsRequested |= 0x8;
5964 this.checkIRQMatching();
5967 this.serialShiftTimer -= this.CPUTicks;
5968 if (this.serialShiftTimer <= 0) {
5969 this.serialShiftTimer = this.serialShiftTimerAllocated;
5970 this.memory[0xFF01] = ((this.memory[0xFF01] << 1) & 0xFE) | 0x01; //We could shift in actual link data here if we were to implement such!!!
5974 GameBoyCore.prototype.updateCoreFull = function () {
5975 //Update the state machine:
5977 //End of iteration routine:
5978 if (this.emulatorTicks >= this.CPUCyclesTotal) {
5979 this.iterationEndRoutine();
5982 GameBoyCore.prototype.initializeLCDController = function () {
5983 //Display on hanlding:
5985 while (line < 154) {
5987 //We're on a normal scan line:
5988 this.LINECONTROL[line] = function (parentObj) {
5989 if (parentObj.LCDTicks < 80) {
5990 parentObj.scanLineMode2();
5992 else if (parentObj.LCDTicks < 252) {
5993 parentObj.scanLineMode3();
5995 else if (parentObj.LCDTicks < 456) {
5996 parentObj.scanLineMode0();
5999 //We're on a new scan line:
6000 parentObj.LCDTicks -= 456;
6001 if (parentObj.STATTracker != 3) {
6002 //Make sure the mode 0 handler was run at least once per scan line:
6003 if (parentObj.STATTracker != 2) {
6004 if (parentObj.STATTracker == 0 && parentObj.mode2TriggerSTAT) {
6005 parentObj.interruptsRequested |= 0x2;
6007 parentObj.incrementScanLineQueue();
6009 if (parentObj.hdmaRunning) {
6010 parentObj.executeHDMA();
6012 if (parentObj.mode0TriggerSTAT) {
6013 parentObj.interruptsRequested |= 0x2;
6016 //Update the scanline registers and assert the LYC counter:
6017 parentObj.actualScanLine = ++parentObj.memory[0xFF44];
6018 //Perform a LYC counter assert:
6019 if (parentObj.actualScanLine == parentObj.memory[0xFF45]) {
6020 parentObj.memory[0xFF41] |= 0x04;
6021 if (parentObj.LYCMatchTriggerSTAT) {
6022 parentObj.interruptsRequested |= 0x2;
6026 parentObj.memory[0xFF41] &= 0x7B;
6028 parentObj.checkIRQMatching();
6029 //Reset our mode contingency variables:
6030 parentObj.STATTracker = 0;
6031 parentObj.modeSTAT = 2;
6032 parentObj.LINECONTROL[parentObj.actualScanLine](parentObj); //Scan Line and STAT Mode Control.
6036 else if (line == 143) {
6037 //We're on the last visible scan line of the LCD screen:
6038 this.LINECONTROL[143] = function (parentObj) {
6039 if (parentObj.LCDTicks < 80) {
6040 parentObj.scanLineMode2();
6042 else if (parentObj.LCDTicks < 252) {
6043 parentObj.scanLineMode3();
6045 else if (parentObj.LCDTicks < 456) {
6046 parentObj.scanLineMode0();
6050 //Just finished the last visible scan line:
6051 parentObj.LCDTicks -= 456;
6052 if (parentObj.STATTracker != 3) {
6053 //Make sure the mode 0 handler was run at least once per scan line:
6054 if (parentObj.STATTracker != 2) {
6055 if (parentObj.STATTracker == 0 && parentObj.mode2TriggerSTAT) {
6056 parentObj.interruptsRequested |= 0x2;
6058 parentObj.incrementScanLineQueue();
6060 if (parentObj.hdmaRunning) {
6061 parentObj.executeHDMA();
6063 if (parentObj.mode0TriggerSTAT) {
6064 parentObj.interruptsRequested |= 0x2;
6067 //Update the scanline registers and assert the LYC counter:
6068 parentObj.actualScanLine = parentObj.memory[0xFF44] = 144;
6069 //Perform a LYC counter assert:
6070 if (parentObj.memory[0xFF45] == 144) {
6071 parentObj.memory[0xFF41] |= 0x04;
6072 if (parentObj.LYCMatchTriggerSTAT) {
6073 parentObj.interruptsRequested |= 0x2;
6077 parentObj.memory[0xFF41] &= 0x7B;
6079 //Reset our mode contingency variables:
6080 parentObj.STATTracker = 0;
6081 //Update our state for v-blank:
6082 parentObj.modeSTAT = 1;
6083 parentObj.interruptsRequested |= (parentObj.mode1TriggerSTAT) ? 0x3 : 0x1;
6084 parentObj.checkIRQMatching();
6085 //Attempt to blit out to our canvas:
6086 if (parentObj.drewBlank == 0) {
6087 //Ensure JIT framing alignment:
6088 if (parentObj.totalLinesPassed < 144 || (parentObj.totalLinesPassed == 144 && parentObj.midScanlineOffset > -1)) {
6089 //Make sure our gfx are up-to-date:
6090 parentObj.graphicsJITVBlank();
6092 parentObj.prepareFrame();
6096 //LCD off takes at least 2 frames:
6097 --parentObj.drewBlank;
6099 parentObj.LINECONTROL[144](parentObj); //Scan Line and STAT Mode Control.
6103 else if (line < 153) {
6105 this.LINECONTROL[line] = function (parentObj) {
6106 if (parentObj.LCDTicks >= 456) {
6107 //We're on a new scan line:
6108 parentObj.LCDTicks -= 456;
6109 parentObj.actualScanLine = ++parentObj.memory[0xFF44];
6110 //Perform a LYC counter assert:
6111 if (parentObj.actualScanLine == parentObj.memory[0xFF45]) {
6112 parentObj.memory[0xFF41] |= 0x04;
6113 if (parentObj.LYCMatchTriggerSTAT) {
6114 parentObj.interruptsRequested |= 0x2;
6115 parentObj.checkIRQMatching();
6119 parentObj.memory[0xFF41] &= 0x7B;
6121 parentObj.LINECONTROL[parentObj.actualScanLine](parentObj); //Scan Line and STAT Mode Control.
6126 //VBlank Ending (We're on the last actual scan line)
6127 this.LINECONTROL[153] = function (parentObj) {
6128 if (parentObj.LCDTicks >= 8) {
6129 if (parentObj.STATTracker != 4 && parentObj.memory[0xFF44] == 153) {
6130 parentObj.memory[0xFF44] = 0; //LY register resets to 0 early.
6131 //Perform a LYC counter assert:
6132 if (parentObj.memory[0xFF45] == 0) {
6133 parentObj.memory[0xFF41] |= 0x04;
6134 if (parentObj.LYCMatchTriggerSTAT) {
6135 parentObj.interruptsRequested |= 0x2;
6136 parentObj.checkIRQMatching();
6140 parentObj.memory[0xFF41] &= 0x7B;
6142 parentObj.STATTracker = 4;
6144 if (parentObj.LCDTicks >= 456) {
6145 //We reset back to the beginning:
6146 parentObj.LCDTicks -= 456;
6147 parentObj.STATTracker = parentObj.actualScanLine = 0;
6148 parentObj.LINECONTROL[0](parentObj); //Scan Line and STAT Mode Control.
6156 GameBoyCore.prototype.DisplayShowOff = function () {
6157 if (this.drewBlank == 0) {
6158 //Output a blank screen to the output framebuffer:
6159 this.clearFrameBuffer();
6160 this.drewFrame = true;
6164 GameBoyCore.prototype.executeHDMA = function () {
6167 if ((this.LCDTicks - this.spriteCount) < ((4 >> this.doubleSpeedShifter) | 0x20)) {
6168 //HALT clocking correction:
6169 this.CPUTicks = 4 + ((0x20 + this.spriteCount) << this.doubleSpeedShifter);
6170 this.LCDTicks = this.spriteCount + ((4 >> this.doubleSpeedShifter) | 0x20);
6174 this.LCDTicks += (4 >> this.doubleSpeedShifter) | 0x20; //LCD Timing Update For HDMA.
6176 if (this.memory[0xFF55] == 0) {
6177 this.hdmaRunning = false;
6178 this.memory[0xFF55] = 0xFF; //Transfer completed ("Hidden last step," since some ROMs don't imply this, but most do).
6181 --this.memory[0xFF55];
6184 GameBoyCore.prototype.clockUpdate = function () {
6186 var dateObj = new_Date(); // The line is changed for benchmarking.
6187 var newTime = dateObj.getTime();
6188 var timeElapsed = newTime - this.lastIteration; //Get the numnber of milliseconds since this last executed.
6189 this.lastIteration = newTime;
6190 if (this.cTIMER && !this.RTCHALT) {
6191 //Update the MBC3 RTC:
6192 this.RTCSeconds += timeElapsed / 1000;
6193 while (this.RTCSeconds >= 60) { //System can stutter, so the seconds difference can get large, thus the "while".
6194 this.RTCSeconds -= 60;
6196 if (this.RTCMinutes >= 60) {
6197 this.RTCMinutes -= 60;
6199 if (this.RTCHours >= 24) {
6202 if (this.RTCDays >= 512) {
6203 this.RTCDays -= 512;
6204 this.RTCDayOverFlow = true;
6212 GameBoyCore.prototype.prepareFrame = function () {
6213 //Copy the internal frame buffer to the output buffer:
6214 this.swizzleFrameBuffer();
6215 this.drewFrame = true;
6217 GameBoyCore.prototype.requestDraw = function () {
6218 if (this.drewFrame) {
6219 this.dispatchDraw();
6222 GameBoyCore.prototype.dispatchDraw = function () {
6223 var canvasRGBALength = this.offscreenRGBCount;
6224 if (canvasRGBALength > 0) {
6225 //We actually updated the graphics internally, so copy out:
6226 var frameBuffer = (canvasRGBALength == 92160) ? this.swizzledFrame : this.resizeFrameBuffer();
6227 var canvasData = this.canvasBuffer.data;
6228 var bufferIndex = 0;
6229 for (var canvasIndex = 0; canvasIndex < canvasRGBALength; ++canvasIndex) {
6230 canvasData[canvasIndex++] = frameBuffer[bufferIndex++];
6231 canvasData[canvasIndex++] = frameBuffer[bufferIndex++];
6232 canvasData[canvasIndex++] = frameBuffer[bufferIndex++];
6234 this.graphicsBlit();
6237 GameBoyCore.prototype.swizzleFrameBuffer = function () {
6238 //Convert our dirty 24-bit (24-bit, with internal render flags above it) framebuffer to an 8-bit buffer with separate indices for the RGB channels:
6239 var frameBuffer = this.frameBuffer;
6240 var swizzledFrame = this.swizzledFrame;
6241 var bufferIndex = 0;
6242 for (var canvasIndex = 0; canvasIndex < 69120;) {
6243 swizzledFrame[canvasIndex++] = (frameBuffer[bufferIndex] >> 16) & 0xFF; //Red
6244 swizzledFrame[canvasIndex++] = (frameBuffer[bufferIndex] >> 8) & 0xFF; //Green
6245 swizzledFrame[canvasIndex++] = frameBuffer[bufferIndex++] & 0xFF; //Blue
6248 GameBoyCore.prototype.clearFrameBuffer = function () {
6249 var bufferIndex = 0;
6250 var frameBuffer = this.swizzledFrame;
6251 if (this.cGBC || this.colorizedGBPalettes) {
6252 while (bufferIndex < 69120) {
6253 frameBuffer[bufferIndex++] = 248;
6257 while (bufferIndex < 69120) {
6258 frameBuffer[bufferIndex++] = 239;
6259 frameBuffer[bufferIndex++] = 255;
6260 frameBuffer[bufferIndex++] = 222;
6264 GameBoyCore.prototype.resizeFrameBuffer = function () {
6265 //Return a reference to the generated resized framebuffer:
6266 return this.resizer.resize(this.swizzledFrame);
6268 GameBoyCore.prototype.compileResizeFrameBufferFunction = function () {
6269 if (this.offscreenRGBCount > 0) {
6270 this.resizer = new Resize(160, 144, this.offscreenWidth, this.offscreenHeight, false, true);
6273 GameBoyCore.prototype.renderScanLine = function (scanlineToRender) {
6274 this.pixelStart = scanlineToRender * 160;
6275 if (this.bgEnabled) {
6276 this.pixelEnd = 160;
6277 this.BGLayerRender(scanlineToRender);
6278 this.WindowLayerRender(scanlineToRender);
6281 var pixelLine = (scanlineToRender + 1) * 160;
6282 var defaultColor = (this.cGBC || this.colorizedGBPalettes) ? 0xF8F8F8 : 0xEFFFDE;
6283 for (var pixelPosition = (scanlineToRender * 160) + this.currentX; pixelPosition < pixelLine; pixelPosition++) {
6284 this.frameBuffer[pixelPosition] = defaultColor;
6287 this.SpriteLayerRender(scanlineToRender);
6289 this.midScanlineOffset = -1;
6291 GameBoyCore.prototype.renderMidScanLine = function () {
6292 if (this.actualScanLine < 144 && this.modeSTAT == 3) {
6293 //TODO: Get this accurate:
6294 if (this.midScanlineOffset == -1) {
6295 this.midScanlineOffset = this.backgroundX & 0x7;
6297 if (this.LCDTicks >= 82) {
6298 this.pixelEnd = this.LCDTicks - 74;
6299 this.pixelEnd = Math.min(this.pixelEnd - this.midScanlineOffset - (this.pixelEnd % 0x8), 160);
6300 if (this.bgEnabled) {
6301 this.pixelStart = this.lastUnrenderedLine * 160;
6302 this.BGLayerRender(this.lastUnrenderedLine);
6303 this.WindowLayerRender(this.lastUnrenderedLine);
6304 //TODO: Do midscanline JIT for sprites...
6307 var pixelLine = (this.lastUnrenderedLine * 160) + this.pixelEnd;
6308 var defaultColor = (this.cGBC || this.colorizedGBPalettes) ? 0xF8F8F8 : 0xEFFFDE;
6309 for (var pixelPosition = (this.lastUnrenderedLine * 160) + this.currentX; pixelPosition < pixelLine; pixelPosition++) {
6310 this.frameBuffer[pixelPosition] = defaultColor;
6313 this.currentX = this.pixelEnd;
6317 GameBoyCore.prototype.initializeModeSpecificArrays = function () {
6318 this.LCDCONTROL = (this.LCDisOn) ? this.LINECONTROL : this.DISPLAYOFFCONTROL;
6320 this.gbcOBJRawPalette = this.getTypedArray(0x40, 0, "uint8");
6321 this.gbcBGRawPalette = this.getTypedArray(0x40, 0, "uint8");
6322 this.gbcOBJPalette = this.getTypedArray(0x20, 0x1000000, "int32");
6323 this.gbcBGPalette = this.getTypedArray(0x40, 0, "int32");
6324 this.BGCHRBank2 = this.getTypedArray(0x800, 0, "uint8");
6325 this.BGCHRCurrentBank = (this.currVRAMBank > 0) ? this.BGCHRBank2 : this.BGCHRBank1;
6326 this.tileCache = this.generateCacheArray(0xF80);
6329 this.gbOBJPalette = this.getTypedArray(8, 0, "int32");
6330 this.gbBGPalette = this.getTypedArray(4, 0, "int32");
6331 this.BGPalette = this.gbBGPalette;
6332 this.OBJPalette = this.gbOBJPalette;
6333 this.tileCache = this.generateCacheArray(0x700);
6334 this.sortBuffer = this.getTypedArray(0x100, 0, "uint8");
6335 this.OAMAddressCache = this.getTypedArray(10, 0, "int32");
6337 this.renderPathBuild();
6339 GameBoyCore.prototype.GBCtoGBModeAdjust = function () {
6340 cout("Stepping down from GBC mode.", 0);
6341 this.VRAM = this.GBCMemory = this.BGCHRCurrentBank = this.BGCHRBank2 = null;
6342 this.tileCache.length = 0x700;
6344 this.gbBGColorizedPalette = this.getTypedArray(4, 0, "int32");
6345 this.gbOBJColorizedPalette = this.getTypedArray(8, 0, "int32");
6346 this.cachedBGPaletteConversion = this.getTypedArray(4, 0, "int32");
6347 this.cachedOBJPaletteConversion = this.getTypedArray(8, 0, "int32");
6348 this.BGPalette = this.gbBGColorizedPalette;
6349 this.OBJPalette = this.gbOBJColorizedPalette;
6350 this.gbOBJPalette = this.gbBGPalette = null;
6354 this.gbOBJPalette = this.getTypedArray(8, 0, "int32");
6355 this.gbBGPalette = this.getTypedArray(4, 0, "int32");
6356 this.BGPalette = this.gbBGPalette;
6357 this.OBJPalette = this.gbOBJPalette;
6359 this.sortBuffer = this.getTypedArray(0x100, 0, "uint8");
6360 this.OAMAddressCache = this.getTypedArray(10, 0, "int32");
6361 this.renderPathBuild();
6362 this.memoryReadJumpCompile();
6363 this.memoryWriteJumpCompile();
6365 GameBoyCore.prototype.renderPathBuild = function () {
6367 this.BGLayerRender = this.BGGBLayerRender;
6368 this.WindowLayerRender = this.WindowGBLayerRender;
6369 this.SpriteLayerRender = this.SpriteGBLayerRender;
6372 this.priorityFlaggingPathRebuild();
6373 this.SpriteLayerRender = this.SpriteGBCLayerRender;
6376 GameBoyCore.prototype.priorityFlaggingPathRebuild = function () {
6377 if (this.BGPriorityEnabled) {
6378 this.BGLayerRender = this.BGGBCLayerRender;
6379 this.WindowLayerRender = this.WindowGBCLayerRender;
6382 this.BGLayerRender = this.BGGBCLayerRenderNoPriorityFlagging;
6383 this.WindowLayerRender = this.WindowGBCLayerRenderNoPriorityFlagging;
6386 GameBoyCore.prototype.initializeReferencesFromSaveState = function () {
6387 this.LCDCONTROL = (this.LCDisOn) ? this.LINECONTROL : this.DISPLAYOFFCONTROL;
6390 if (this.colorizedGBPalettes) {
6391 this.BGPalette = this.gbBGColorizedPalette;
6392 this.OBJPalette = this.gbOBJColorizedPalette;
6393 this.updateGBBGPalette = this.updateGBColorizedBGPalette;
6394 this.updateGBOBJPalette = this.updateGBColorizedOBJPalette;
6398 this.BGPalette = this.gbBGPalette;
6399 this.OBJPalette = this.gbOBJPalette;
6401 this.tileCache = this.generateCacheArray(0x700);
6402 for (tileIndex = 0x8000; tileIndex < 0x9000; tileIndex += 2) {
6403 this.generateGBOAMTileLine(tileIndex);
6405 for (tileIndex = 0x9000; tileIndex < 0x9800; tileIndex += 2) {
6406 this.generateGBTileLine(tileIndex);
6408 this.sortBuffer = this.getTypedArray(0x100, 0, "uint8");
6409 this.OAMAddressCache = this.getTypedArray(10, 0, "int32");
6412 this.BGCHRCurrentBank = (this.currVRAMBank > 0) ? this.BGCHRBank2 : this.BGCHRBank1;
6413 this.tileCache = this.generateCacheArray(0xF80);
6414 for (; tileIndex < 0x1800; tileIndex += 0x10) {
6415 this.generateGBCTileBank1(tileIndex);
6416 this.generateGBCTileBank2(tileIndex);
6419 this.renderPathBuild();
6421 GameBoyCore.prototype.RGBTint = function (value) {
6422 //Adjustment for the GBC's tinting (According to Gambatte):
6423 var r = value & 0x1F;
6424 var g = (value >> 5) & 0x1F;
6425 var b = (value >> 10) & 0x1F;
6426 return ((r * 13 + g * 2 + b) >> 1) << 16 | (g * 3 + b) << 9 | (r * 3 + g * 2 + b * 11) >> 1;
6428 GameBoyCore.prototype.getGBCColor = function () {
6429 //GBC Colorization of DMG ROMs:
6431 for (var counter = 0; counter < 4; counter++) {
6432 var adjustedIndex = counter << 1;
6434 this.cachedBGPaletteConversion[counter] = this.RGBTint((this.gbcBGRawPalette[adjustedIndex | 1] << 8) | this.gbcBGRawPalette[adjustedIndex]);
6436 this.cachedOBJPaletteConversion[counter] = this.RGBTint((this.gbcOBJRawPalette[adjustedIndex | 1] << 8) | this.gbcOBJRawPalette[adjustedIndex]);
6439 for (counter = 4; counter < 8; counter++) {
6440 adjustedIndex = counter << 1;
6441 this.cachedOBJPaletteConversion[counter] = this.RGBTint((this.gbcOBJRawPalette[adjustedIndex | 1] << 8) | this.gbcOBJRawPalette[adjustedIndex]);
6443 //Update the palette entries:
6444 this.updateGBBGPalette = this.updateGBColorizedBGPalette;
6445 this.updateGBOBJPalette = this.updateGBColorizedOBJPalette;
6446 this.updateGBBGPalette(this.memory[0xFF47]);
6447 this.updateGBOBJPalette(0, this.memory[0xFF48]);
6448 this.updateGBOBJPalette(1, this.memory[0xFF49]);
6449 this.colorizedGBPalettes = true;
6451 GameBoyCore.prototype.updateGBRegularBGPalette = function (data) {
6452 this.gbBGPalette[0] = this.colors[data & 0x03] | 0x2000000;
6453 this.gbBGPalette[1] = this.colors[(data >> 2) & 0x03];
6454 this.gbBGPalette[2] = this.colors[(data >> 4) & 0x03];
6455 this.gbBGPalette[3] = this.colors[data >> 6];
6457 GameBoyCore.prototype.updateGBColorizedBGPalette = function (data) {
6459 this.gbBGColorizedPalette[0] = this.cachedBGPaletteConversion[data & 0x03] | 0x2000000;
6460 this.gbBGColorizedPalette[1] = this.cachedBGPaletteConversion[(data >> 2) & 0x03];
6461 this.gbBGColorizedPalette[2] = this.cachedBGPaletteConversion[(data >> 4) & 0x03];
6462 this.gbBGColorizedPalette[3] = this.cachedBGPaletteConversion[data >> 6];
6464 GameBoyCore.prototype.updateGBRegularOBJPalette = function (index, data) {
6465 this.gbOBJPalette[index | 1] = this.colors[(data >> 2) & 0x03];
6466 this.gbOBJPalette[index | 2] = this.colors[(data >> 4) & 0x03];
6467 this.gbOBJPalette[index | 3] = this.colors[data >> 6];
6469 GameBoyCore.prototype.updateGBColorizedOBJPalette = function (index, data) {
6471 this.gbOBJColorizedPalette[index | 1] = this.cachedOBJPaletteConversion[index | ((data >> 2) & 0x03)];
6472 this.gbOBJColorizedPalette[index | 2] = this.cachedOBJPaletteConversion[index | ((data >> 4) & 0x03)];
6473 this.gbOBJColorizedPalette[index | 3] = this.cachedOBJPaletteConversion[index | (data >> 6)];
6475 GameBoyCore.prototype.updateGBCBGPalette = function (index, data) {
6476 if (this.gbcBGRawPalette[index] != data) {
6477 this.midScanLineJIT();
6478 //Update the color palette for BG tiles since it changed:
6479 this.gbcBGRawPalette[index] = data;
6480 if ((index & 0x06) == 0) {
6481 //Palette 0 (Special tile Priority stuff)
6482 data = 0x2000000 | this.RGBTint((this.gbcBGRawPalette[index | 1] << 8) | this.gbcBGRawPalette[index & 0x3E]);
6484 this.gbcBGPalette[index] = data;
6485 this.gbcBGPalette[0x20 | index] = 0x1000000 | data;
6488 //Regular Palettes (No special crap)
6489 data = this.RGBTint((this.gbcBGRawPalette[index | 1] << 8) | this.gbcBGRawPalette[index & 0x3E]);
6491 this.gbcBGPalette[index] = data;
6492 this.gbcBGPalette[0x20 | index] = 0x1000000 | data;
6496 GameBoyCore.prototype.updateGBCOBJPalette = function (index, data) {
6497 if (this.gbcOBJRawPalette[index] != data) {
6498 //Update the color palette for OBJ tiles since it changed:
6499 this.gbcOBJRawPalette[index] = data;
6500 if ((index & 0x06) > 0) {
6501 //Regular Palettes (No special crap)
6502 this.midScanLineJIT();
6503 this.gbcOBJPalette[index >> 1] = 0x1000000 | this.RGBTint((this.gbcOBJRawPalette[index | 1] << 8) | this.gbcOBJRawPalette[index & 0x3E]);
6507 GameBoyCore.prototype.BGGBLayerRender = function (scanlineToRender) {
6508 var scrollYAdjusted = (this.backgroundY + scanlineToRender) & 0xFF; //The line of the BG we're at.
6509 var tileYLine = (scrollYAdjusted & 7) << 3;
6510 var tileYDown = this.gfxBackgroundCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2); //The row of cached tiles we're fetching from.
6511 var scrollXAdjusted = (this.backgroundX + this.currentX) & 0xFF; //The scroll amount of the BG.
6512 var pixelPosition = this.pixelStart + this.currentX; //Current pixel we're working on.
6513 var pixelPositionEnd = this.pixelStart + ((this.gfxWindowDisplay && (scanlineToRender - this.windowY) >= 0) ? Math.min(Math.max(this.windowX, 0) + this.currentX, this.pixelEnd) : this.pixelEnd); //Make sure we do at most 160 pixels a scanline.
6514 var tileNumber = tileYDown + (scrollXAdjusted >> 3);
6515 var chrCode = this.BGCHRBank1[tileNumber];
6516 if (chrCode < this.gfxBackgroundBankOffset) {
6519 var tile = this.tileCache[chrCode];
6520 for (var texel = (scrollXAdjusted & 0x7); texel < 8 && pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
6521 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[tileYLine | texel++]];
6523 var scrollXAdjustedAligned = Math.min(pixelPositionEnd - pixelPosition, 0x100 - scrollXAdjusted) >> 3;
6524 scrollXAdjusted += scrollXAdjustedAligned << 3;
6525 scrollXAdjustedAligned += tileNumber;
6526 while (tileNumber < scrollXAdjustedAligned) {
6527 chrCode = this.BGCHRBank1[++tileNumber];
6528 if (chrCode < this.gfxBackgroundBankOffset) {
6531 tile = this.tileCache[chrCode];
6533 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6534 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6535 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6536 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6537 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6538 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6539 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6540 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel]];
6542 if (pixelPosition < pixelPositionEnd) {
6543 if (scrollXAdjusted < 0x100) {
6544 chrCode = this.BGCHRBank1[++tileNumber];
6545 if (chrCode < this.gfxBackgroundBankOffset) {
6548 tile = this.tileCache[chrCode];
6549 for (texel = tileYLine - 1; pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
6550 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[++texel]];
6553 scrollXAdjustedAligned = ((pixelPositionEnd - pixelPosition) >> 3) + tileYDown;
6554 while (tileYDown < scrollXAdjustedAligned) {
6555 chrCode = this.BGCHRBank1[tileYDown++];
6556 if (chrCode < this.gfxBackgroundBankOffset) {
6559 tile = this.tileCache[chrCode];
6561 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6562 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6563 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6564 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6565 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6566 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6567 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6568 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel]];
6570 if (pixelPosition < pixelPositionEnd) {
6571 chrCode = this.BGCHRBank1[tileYDown];
6572 if (chrCode < this.gfxBackgroundBankOffset) {
6575 tile = this.tileCache[chrCode];
6576 switch (pixelPositionEnd - pixelPosition) {
6578 this.frameBuffer[pixelPosition + 6] = this.BGPalette[tile[tileYLine | 6]];
6580 this.frameBuffer[pixelPosition + 5] = this.BGPalette[tile[tileYLine | 5]];
6582 this.frameBuffer[pixelPosition + 4] = this.BGPalette[tile[tileYLine | 4]];
6584 this.frameBuffer[pixelPosition + 3] = this.BGPalette[tile[tileYLine | 3]];
6586 this.frameBuffer[pixelPosition + 2] = this.BGPalette[tile[tileYLine | 2]];
6588 this.frameBuffer[pixelPosition + 1] = this.BGPalette[tile[tileYLine | 1]];
6590 this.frameBuffer[pixelPosition] = this.BGPalette[tile[tileYLine]];
6595 GameBoyCore.prototype.BGGBCLayerRender = function (scanlineToRender) {
6596 var scrollYAdjusted = (this.backgroundY + scanlineToRender) & 0xFF; //The line of the BG we're at.
6597 var tileYLine = (scrollYAdjusted & 7) << 3;
6598 var tileYDown = this.gfxBackgroundCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2); //The row of cached tiles we're fetching from.
6599 var scrollXAdjusted = (this.backgroundX + this.currentX) & 0xFF; //The scroll amount of the BG.
6600 var pixelPosition = this.pixelStart + this.currentX; //Current pixel we're working on.
6601 var pixelPositionEnd = this.pixelStart + ((this.gfxWindowDisplay && (scanlineToRender - this.windowY) >= 0) ? Math.min(Math.max(this.windowX, 0) + this.currentX, this.pixelEnd) : this.pixelEnd); //Make sure we do at most 160 pixels a scanline.
6602 var tileNumber = tileYDown + (scrollXAdjusted >> 3);
6603 var chrCode = this.BGCHRBank1[tileNumber];
6604 if (chrCode < this.gfxBackgroundBankOffset) {
6607 var attrCode = this.BGCHRBank2[tileNumber];
6608 var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6609 var palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6610 for (var texel = (scrollXAdjusted & 0x7); texel < 8 && pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
6611 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
6613 var scrollXAdjustedAligned = Math.min(pixelPositionEnd - pixelPosition, 0x100 - scrollXAdjusted) >> 3;
6614 scrollXAdjusted += scrollXAdjustedAligned << 3;
6615 scrollXAdjustedAligned += tileNumber;
6616 while (tileNumber < scrollXAdjustedAligned) {
6617 chrCode = this.BGCHRBank1[++tileNumber];
6618 if (chrCode < this.gfxBackgroundBankOffset) {
6621 attrCode = this.BGCHRBank2[tileNumber];
6622 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6623 palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6625 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6626 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6627 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6628 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6629 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6630 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6631 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6632 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
6634 if (pixelPosition < pixelPositionEnd) {
6635 if (scrollXAdjusted < 0x100) {
6636 chrCode = this.BGCHRBank1[++tileNumber];
6637 if (chrCode < this.gfxBackgroundBankOffset) {
6640 attrCode = this.BGCHRBank2[tileNumber];
6641 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6642 palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6643 for (texel = tileYLine - 1; pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
6644 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[++texel]];
6647 scrollXAdjustedAligned = ((pixelPositionEnd - pixelPosition) >> 3) + tileYDown;
6648 while (tileYDown < scrollXAdjustedAligned) {
6649 chrCode = this.BGCHRBank1[tileYDown];
6650 if (chrCode < this.gfxBackgroundBankOffset) {
6653 attrCode = this.BGCHRBank2[tileYDown++];
6654 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6655 palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6657 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6658 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6659 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6660 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6661 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6662 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6663 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6664 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
6666 if (pixelPosition < pixelPositionEnd) {
6667 chrCode = this.BGCHRBank1[tileYDown];
6668 if (chrCode < this.gfxBackgroundBankOffset) {
6671 attrCode = this.BGCHRBank2[tileYDown];
6672 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6673 palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6674 switch (pixelPositionEnd - pixelPosition) {
6676 this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
6678 this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
6680 this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
6682 this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
6684 this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
6686 this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
6688 this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
6693 GameBoyCore.prototype.BGGBCLayerRenderNoPriorityFlagging = function (scanlineToRender) {
6694 var scrollYAdjusted = (this.backgroundY + scanlineToRender) & 0xFF; //The line of the BG we're at.
6695 var tileYLine = (scrollYAdjusted & 7) << 3;
6696 var tileYDown = this.gfxBackgroundCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2); //The row of cached tiles we're fetching from.
6697 var scrollXAdjusted = (this.backgroundX + this.currentX) & 0xFF; //The scroll amount of the BG.
6698 var pixelPosition = this.pixelStart + this.currentX; //Current pixel we're working on.
6699 var pixelPositionEnd = this.pixelStart + ((this.gfxWindowDisplay && (scanlineToRender - this.windowY) >= 0) ? Math.min(Math.max(this.windowX, 0) + this.currentX, this.pixelEnd) : this.pixelEnd); //Make sure we do at most 160 pixels a scanline.
6700 var tileNumber = tileYDown + (scrollXAdjusted >> 3);
6701 var chrCode = this.BGCHRBank1[tileNumber];
6702 if (chrCode < this.gfxBackgroundBankOffset) {
6705 var attrCode = this.BGCHRBank2[tileNumber];
6706 var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6707 var palette = (attrCode & 0x7) << 2;
6708 for (var texel = (scrollXAdjusted & 0x7); texel < 8 && pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
6709 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
6711 var scrollXAdjustedAligned = Math.min(pixelPositionEnd - pixelPosition, 0x100 - scrollXAdjusted) >> 3;
6712 scrollXAdjusted += scrollXAdjustedAligned << 3;
6713 scrollXAdjustedAligned += tileNumber;
6714 while (tileNumber < scrollXAdjustedAligned) {
6715 chrCode = this.BGCHRBank1[++tileNumber];
6716 if (chrCode < this.gfxBackgroundBankOffset) {
6719 attrCode = this.BGCHRBank2[tileNumber];
6720 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6721 palette = (attrCode & 0x7) << 2;
6723 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6724 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6725 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6726 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6727 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6728 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6729 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6730 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
6732 if (pixelPosition < pixelPositionEnd) {
6733 if (scrollXAdjusted < 0x100) {
6734 chrCode = this.BGCHRBank1[++tileNumber];
6735 if (chrCode < this.gfxBackgroundBankOffset) {
6738 attrCode = this.BGCHRBank2[tileNumber];
6739 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6740 palette = (attrCode & 0x7) << 2;
6741 for (texel = tileYLine - 1; pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
6742 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[++texel]];
6745 scrollXAdjustedAligned = ((pixelPositionEnd - pixelPosition) >> 3) + tileYDown;
6746 while (tileYDown < scrollXAdjustedAligned) {
6747 chrCode = this.BGCHRBank1[tileYDown];
6748 if (chrCode < this.gfxBackgroundBankOffset) {
6751 attrCode = this.BGCHRBank2[tileYDown++];
6752 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6753 palette = (attrCode & 0x7) << 2;
6755 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6756 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6757 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6758 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6759 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6760 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6761 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6762 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
6764 if (pixelPosition < pixelPositionEnd) {
6765 chrCode = this.BGCHRBank1[tileYDown];
6766 if (chrCode < this.gfxBackgroundBankOffset) {
6769 attrCode = this.BGCHRBank2[tileYDown];
6770 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6771 palette = (attrCode & 0x7) << 2;
6772 switch (pixelPositionEnd - pixelPosition) {
6774 this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
6776 this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
6778 this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
6780 this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
6782 this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
6784 this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
6786 this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
6791 GameBoyCore.prototype.WindowGBLayerRender = function (scanlineToRender) {
6792 if (this.gfxWindowDisplay) { //Is the window enabled?
6793 var scrollYAdjusted = scanlineToRender - this.windowY; //The line of the BG we're at.
6794 if (scrollYAdjusted >= 0) {
6795 var scrollXRangeAdjusted = (this.windowX > 0) ? (this.windowX + this.currentX) : this.currentX;
6796 var pixelPosition = this.pixelStart + scrollXRangeAdjusted;
6797 var pixelPositionEnd = this.pixelStart + this.pixelEnd;
6798 if (pixelPosition < pixelPositionEnd) {
6799 var tileYLine = (scrollYAdjusted & 0x7) << 3;
6800 var tileNumber = (this.gfxWindowCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2)) + (this.currentX >> 3);
6801 var chrCode = this.BGCHRBank1[tileNumber];
6802 if (chrCode < this.gfxBackgroundBankOffset) {
6805 var tile = this.tileCache[chrCode];
6806 var texel = (scrollXRangeAdjusted - this.windowX) & 0x7;
6807 scrollXRangeAdjusted = Math.min(8, texel + pixelPositionEnd - pixelPosition);
6808 while (texel < scrollXRangeAdjusted) {
6809 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[tileYLine | texel++]];
6811 scrollXRangeAdjusted = tileNumber + ((pixelPositionEnd - pixelPosition) >> 3);
6812 while (tileNumber < scrollXRangeAdjusted) {
6813 chrCode = this.BGCHRBank1[++tileNumber];
6814 if (chrCode < this.gfxBackgroundBankOffset) {
6817 tile = this.tileCache[chrCode];
6819 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6820 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6821 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6822 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6823 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6824 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6825 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
6826 this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel]];
6828 if (pixelPosition < pixelPositionEnd) {
6829 chrCode = this.BGCHRBank1[++tileNumber];
6830 if (chrCode < this.gfxBackgroundBankOffset) {
6833 tile = this.tileCache[chrCode];
6834 switch (pixelPositionEnd - pixelPosition) {
6836 this.frameBuffer[pixelPosition + 6] = this.BGPalette[tile[tileYLine | 6]];
6838 this.frameBuffer[pixelPosition + 5] = this.BGPalette[tile[tileYLine | 5]];
6840 this.frameBuffer[pixelPosition + 4] = this.BGPalette[tile[tileYLine | 4]];
6842 this.frameBuffer[pixelPosition + 3] = this.BGPalette[tile[tileYLine | 3]];
6844 this.frameBuffer[pixelPosition + 2] = this.BGPalette[tile[tileYLine | 2]];
6846 this.frameBuffer[pixelPosition + 1] = this.BGPalette[tile[tileYLine | 1]];
6848 this.frameBuffer[pixelPosition] = this.BGPalette[tile[tileYLine]];
6855 GameBoyCore.prototype.WindowGBCLayerRender = function (scanlineToRender) {
6856 if (this.gfxWindowDisplay) { //Is the window enabled?
6857 var scrollYAdjusted = scanlineToRender - this.windowY; //The line of the BG we're at.
6858 if (scrollYAdjusted >= 0) {
6859 var scrollXRangeAdjusted = (this.windowX > 0) ? (this.windowX + this.currentX) : this.currentX;
6860 var pixelPosition = this.pixelStart + scrollXRangeAdjusted;
6861 var pixelPositionEnd = this.pixelStart + this.pixelEnd;
6862 if (pixelPosition < pixelPositionEnd) {
6863 var tileYLine = (scrollYAdjusted & 0x7) << 3;
6864 var tileNumber = (this.gfxWindowCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2)) + (this.currentX >> 3);
6865 var chrCode = this.BGCHRBank1[tileNumber];
6866 if (chrCode < this.gfxBackgroundBankOffset) {
6869 var attrCode = this.BGCHRBank2[tileNumber];
6870 var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6871 var palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6872 var texel = (scrollXRangeAdjusted - this.windowX) & 0x7;
6873 scrollXRangeAdjusted = Math.min(8, texel + pixelPositionEnd - pixelPosition);
6874 while (texel < scrollXRangeAdjusted) {
6875 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
6877 scrollXRangeAdjusted = tileNumber + ((pixelPositionEnd - pixelPosition) >> 3);
6878 while (tileNumber < scrollXRangeAdjusted) {
6879 chrCode = this.BGCHRBank1[++tileNumber];
6880 if (chrCode < this.gfxBackgroundBankOffset) {
6883 attrCode = this.BGCHRBank2[tileNumber];
6884 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6885 palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6887 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6888 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6889 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6890 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6891 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6892 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6893 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6894 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
6896 if (pixelPosition < pixelPositionEnd) {
6897 chrCode = this.BGCHRBank1[++tileNumber];
6898 if (chrCode < this.gfxBackgroundBankOffset) {
6901 attrCode = this.BGCHRBank2[tileNumber];
6902 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6903 palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
6904 switch (pixelPositionEnd - pixelPosition) {
6906 this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
6908 this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
6910 this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
6912 this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
6914 this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
6916 this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
6918 this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
6925 GameBoyCore.prototype.WindowGBCLayerRenderNoPriorityFlagging = function (scanlineToRender) {
6926 if (this.gfxWindowDisplay) { //Is the window enabled?
6927 var scrollYAdjusted = scanlineToRender - this.windowY; //The line of the BG we're at.
6928 if (scrollYAdjusted >= 0) {
6929 var scrollXRangeAdjusted = (this.windowX > 0) ? (this.windowX + this.currentX) : this.currentX;
6930 var pixelPosition = this.pixelStart + scrollXRangeAdjusted;
6931 var pixelPositionEnd = this.pixelStart + this.pixelEnd;
6932 if (pixelPosition < pixelPositionEnd) {
6933 var tileYLine = (scrollYAdjusted & 0x7) << 3;
6934 var tileNumber = (this.gfxWindowCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2)) + (this.currentX >> 3);
6935 var chrCode = this.BGCHRBank1[tileNumber];
6936 if (chrCode < this.gfxBackgroundBankOffset) {
6939 var attrCode = this.BGCHRBank2[tileNumber];
6940 var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6941 var palette = (attrCode & 0x7) << 2;
6942 var texel = (scrollXRangeAdjusted - this.windowX) & 0x7;
6943 scrollXRangeAdjusted = Math.min(8, texel + pixelPositionEnd - pixelPosition);
6944 while (texel < scrollXRangeAdjusted) {
6945 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
6947 scrollXRangeAdjusted = tileNumber + ((pixelPositionEnd - pixelPosition) >> 3);
6948 while (tileNumber < scrollXRangeAdjusted) {
6949 chrCode = this.BGCHRBank1[++tileNumber];
6950 if (chrCode < this.gfxBackgroundBankOffset) {
6953 attrCode = this.BGCHRBank2[tileNumber];
6954 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6955 palette = (attrCode & 0x7) << 2;
6957 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6958 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6959 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6960 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6961 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6962 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6963 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
6964 this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
6966 if (pixelPosition < pixelPositionEnd) {
6967 chrCode = this.BGCHRBank1[++tileNumber];
6968 if (chrCode < this.gfxBackgroundBankOffset) {
6971 attrCode = this.BGCHRBank2[tileNumber];
6972 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
6973 palette = (attrCode & 0x7) << 2;
6974 switch (pixelPositionEnd - pixelPosition) {
6976 this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
6978 this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
6980 this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
6982 this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
6984 this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
6986 this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
6988 this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
6995 GameBoyCore.prototype.SpriteGBLayerRender = function (scanlineToRender) {
6996 if (this.gfxSpriteShow) { //Are sprites enabled?
6997 var lineAdjusted = scanlineToRender + 0x10;
6998 var OAMAddress = 0xFE00;
7001 var xCoordStart = 0;
7007 var spriteCount = 0;
7009 var currentPixel = 0;
7011 //Clear our x-coord sort buffer:
7012 while (xcoord < 168) {
7013 this.sortBuffer[xcoord++] = 0xFF;
7015 if (this.gfxSpriteNormalHeight) {
7016 //Draw the visible sprites:
7017 for (var length = this.findLowestSpriteDrawable(lineAdjusted, 0x7); spriteCount < length; ++spriteCount) {
7018 OAMAddress = this.OAMAddressCache[spriteCount];
7019 yoffset = (lineAdjusted - this.memory[OAMAddress]) << 3;
7020 attrCode = this.memory[OAMAddress | 3];
7021 palette = (attrCode & 0x10) >> 2;
7022 tile = this.tileCache[((attrCode & 0x60) << 4) | this.memory[OAMAddress | 0x2]];
7023 linePixel = xCoordStart = this.memory[OAMAddress | 1];
7024 xCoordEnd = Math.min(168 - linePixel, 8);
7025 xcoord = (linePixel > 7) ? 0 : (8 - linePixel);
7026 for (currentPixel = this.pixelStart + ((linePixel > 8) ? (linePixel - 8) : 0); xcoord < xCoordEnd; ++xcoord, ++currentPixel, ++linePixel) {
7027 if (this.sortBuffer[linePixel] > xCoordStart) {
7028 if (this.frameBuffer[currentPixel] >= 0x2000000) {
7029 data = tile[yoffset | xcoord];
7031 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
7032 this.sortBuffer[linePixel] = xCoordStart;
7035 else if (this.frameBuffer[currentPixel] < 0x1000000) {
7036 data = tile[yoffset | xcoord];
7037 if (data > 0 && attrCode < 0x80) {
7038 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
7039 this.sortBuffer[linePixel] = xCoordStart;
7047 //Draw the visible sprites:
7048 for (var length = this.findLowestSpriteDrawable(lineAdjusted, 0xF); spriteCount < length; ++spriteCount) {
7049 OAMAddress = this.OAMAddressCache[spriteCount];
7050 yoffset = (lineAdjusted - this.memory[OAMAddress]) << 3;
7051 attrCode = this.memory[OAMAddress | 3];
7052 palette = (attrCode & 0x10) >> 2;
7053 if ((attrCode & 0x40) == (0x40 & yoffset)) {
7054 tile = this.tileCache[((attrCode & 0x60) << 4) | (this.memory[OAMAddress | 0x2] & 0xFE)];
7057 tile = this.tileCache[((attrCode & 0x60) << 4) | this.memory[OAMAddress | 0x2] | 1];
7060 linePixel = xCoordStart = this.memory[OAMAddress | 1];
7061 xCoordEnd = Math.min(168 - linePixel, 8);
7062 xcoord = (linePixel > 7) ? 0 : (8 - linePixel);
7063 for (currentPixel = this.pixelStart + ((linePixel > 8) ? (linePixel - 8) : 0); xcoord < xCoordEnd; ++xcoord, ++currentPixel, ++linePixel) {
7064 if (this.sortBuffer[linePixel] > xCoordStart) {
7065 if (this.frameBuffer[currentPixel] >= 0x2000000) {
7066 data = tile[yoffset | xcoord];
7068 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
7069 this.sortBuffer[linePixel] = xCoordStart;
7072 else if (this.frameBuffer[currentPixel] < 0x1000000) {
7073 data = tile[yoffset | xcoord];
7074 if (data > 0 && attrCode < 0x80) {
7075 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
7076 this.sortBuffer[linePixel] = xCoordStart;
7085 GameBoyCore.prototype.findLowestSpriteDrawable = function (scanlineToRender, drawableRange) {
7086 var address = 0xFE00;
7087 var spriteCount = 0;
7089 while (address < 0xFEA0 && spriteCount < 10) {
7090 diff = scanlineToRender - this.memory[address];
7091 if ((diff & drawableRange) == diff) {
7092 this.OAMAddressCache[spriteCount++] = address;
7098 GameBoyCore.prototype.SpriteGBCLayerRender = function (scanlineToRender) {
7099 if (this.gfxSpriteShow) { //Are sprites enabled?
7100 var OAMAddress = 0xFE00;
7101 var lineAdjusted = scanlineToRender + 0x10;
7110 var currentPixel = 0;
7111 var spriteCount = 0;
7112 if (this.gfxSpriteNormalHeight) {
7113 for (; OAMAddress < 0xFEA0 && spriteCount < 10; OAMAddress += 4) {
7114 yoffset = lineAdjusted - this.memory[OAMAddress];
7115 if ((yoffset & 0x7) == yoffset) {
7116 xcoord = this.memory[OAMAddress | 1] - 8;
7117 endX = Math.min(160, xcoord + 8);
7118 attrCode = this.memory[OAMAddress | 3];
7119 palette = (attrCode & 7) << 2;
7120 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | this.memory[OAMAddress | 2]];
7121 xCounter = (xcoord > 0) ? xcoord : 0;
7122 xcoord -= yoffset << 3;
7123 for (currentPixel = this.pixelStart + xCounter; xCounter < endX; ++xCounter, ++currentPixel) {
7124 if (this.frameBuffer[currentPixel] >= 0x2000000) {
7125 data = tile[xCounter - xcoord];
7127 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
7130 else if (this.frameBuffer[currentPixel] < 0x1000000) {
7131 data = tile[xCounter - xcoord];
7132 if (data > 0 && attrCode < 0x80) { //Don't optimize for attrCode, as LICM-capable JITs should optimize its checks.
7133 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
7142 for (; OAMAddress < 0xFEA0 && spriteCount < 10; OAMAddress += 4) {
7143 yoffset = lineAdjusted - this.memory[OAMAddress];
7144 if ((yoffset & 0xF) == yoffset) {
7145 xcoord = this.memory[OAMAddress | 1] - 8;
7146 endX = Math.min(160, xcoord + 8);
7147 attrCode = this.memory[OAMAddress | 3];
7148 palette = (attrCode & 7) << 2;
7149 if ((attrCode & 0x40) == (0x40 & (yoffset << 3))) {
7150 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | (this.memory[OAMAddress | 0x2] & 0xFE)];
7153 tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | this.memory[OAMAddress | 0x2] | 1];
7155 xCounter = (xcoord > 0) ? xcoord : 0;
7156 xcoord -= (yoffset & 0x7) << 3;
7157 for (currentPixel = this.pixelStart + xCounter; xCounter < endX; ++xCounter, ++currentPixel) {
7158 if (this.frameBuffer[currentPixel] >= 0x2000000) {
7159 data = tile[xCounter - xcoord];
7161 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
7164 else if (this.frameBuffer[currentPixel] < 0x1000000) {
7165 data = tile[xCounter - xcoord];
7166 if (data > 0 && attrCode < 0x80) { //Don't optimize for attrCode, as LICM-capable JITs should optimize its checks.
7167 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
7177 //Generate only a single tile line for the GB tile cache mode:
7178 GameBoyCore.prototype.generateGBTileLine = function (address) {
7179 var lineCopy = (this.memory[0x1 | address] << 8) | this.memory[0x9FFE & address];
7180 var tileBlock = this.tileCache[(address & 0x1FF0) >> 4];
7181 address = (address & 0xE) << 2;
7182 tileBlock[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
7183 tileBlock[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
7184 tileBlock[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
7185 tileBlock[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
7186 tileBlock[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
7187 tileBlock[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
7188 tileBlock[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
7189 tileBlock[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
7191 //Generate only a single tile line for the GBC tile cache mode (Bank 1):
7192 GameBoyCore.prototype.generateGBCTileLineBank1 = function (address) {
7193 var lineCopy = (this.memory[0x1 | address] << 8) | this.memory[0x9FFE & address];
7195 var tileBlock1 = this.tileCache[address >> 4];
7196 var tileBlock2 = this.tileCache[0x200 | (address >> 4)];
7197 var tileBlock3 = this.tileCache[0x400 | (address >> 4)];
7198 var tileBlock4 = this.tileCache[0x600 | (address >> 4)];
7199 address = (address & 0xE) << 2;
7200 var addressFlipped = 0x38 - address;
7201 tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
7202 tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
7203 tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
7204 tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
7205 tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
7206 tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
7207 tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
7208 tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
7210 //Generate all the flip combinations for a full GBC VRAM bank 1 tile:
7211 GameBoyCore.prototype.generateGBCTileBank1 = function (vramAddress) {
7212 var address = vramAddress >> 4;
7213 var tileBlock1 = this.tileCache[address];
7214 var tileBlock2 = this.tileCache[0x200 | address];
7215 var tileBlock3 = this.tileCache[0x400 | address];
7216 var tileBlock4 = this.tileCache[0x600 | address];
7218 vramAddress |= 0x8000;
7220 var addressFlipped = 56;
7222 lineCopy = (this.memory[0x1 | vramAddress] << 8) | this.memory[vramAddress];
7223 tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
7224 tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
7225 tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
7226 tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
7227 tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
7228 tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
7229 tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
7230 tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
7232 addressFlipped -= 8;
7234 } while (addressFlipped > -1);
7236 //Generate only a single tile line for the GBC tile cache mode (Bank 2):
7237 GameBoyCore.prototype.generateGBCTileLineBank2 = function (address) {
7238 var lineCopy = (this.VRAM[0x1 | address] << 8) | this.VRAM[0x1FFE & address];
7239 var tileBlock1 = this.tileCache[0x800 | (address >> 4)];
7240 var tileBlock2 = this.tileCache[0xA00 | (address >> 4)];
7241 var tileBlock3 = this.tileCache[0xC00 | (address >> 4)];
7242 var tileBlock4 = this.tileCache[0xE00 | (address >> 4)];
7243 address = (address & 0xE) << 2;
7244 var addressFlipped = 0x38 - address;
7245 tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
7246 tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
7247 tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
7248 tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
7249 tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
7250 tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
7251 tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
7252 tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
7254 //Generate all the flip combinations for a full GBC VRAM bank 2 tile:
7255 GameBoyCore.prototype.generateGBCTileBank2 = function (vramAddress) {
7256 var address = vramAddress >> 4;
7257 var tileBlock1 = this.tileCache[0x800 | address];
7258 var tileBlock2 = this.tileCache[0xA00 | address];
7259 var tileBlock3 = this.tileCache[0xC00 | address];
7260 var tileBlock4 = this.tileCache[0xE00 | address];
7263 var addressFlipped = 56;
7265 lineCopy = (this.VRAM[0x1 | vramAddress] << 8) | this.VRAM[vramAddress];
7266 tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
7267 tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
7268 tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
7269 tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
7270 tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
7271 tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
7272 tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
7273 tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
7275 addressFlipped -= 8;
7277 } while (addressFlipped > -1);
7279 //Generate only a single tile line for the GB tile cache mode (OAM accessible range):
7280 GameBoyCore.prototype.generateGBOAMTileLine = function (address) {
7281 var lineCopy = (this.memory[0x1 | address] << 8) | this.memory[0x9FFE & address];
7283 var tileBlock1 = this.tileCache[address >> 4];
7284 var tileBlock2 = this.tileCache[0x200 | (address >> 4)];
7285 var tileBlock3 = this.tileCache[0x400 | (address >> 4)];
7286 var tileBlock4 = this.tileCache[0x600 | (address >> 4)];
7287 address = (address & 0xE) << 2;
7288 var addressFlipped = 0x38 - address;
7289 tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
7290 tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
7291 tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
7292 tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
7293 tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
7294 tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
7295 tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
7296 tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
7298 GameBoyCore.prototype.graphicsJIT = function () {
7300 this.totalLinesPassed = 0; //Mark frame for ensuring a JIT pass for the next framebuffer output.
7301 this.graphicsJITScanlineGroup();
7304 GameBoyCore.prototype.graphicsJITVBlank = function () {
7305 //JIT the graphics to v-blank framing:
7306 this.totalLinesPassed += this.queuedScanLines;
7307 this.graphicsJITScanlineGroup();
7309 GameBoyCore.prototype.graphicsJITScanlineGroup = function () {
7310 //Normal rendering JIT, where we try to do groups of scanlines at once:
7311 while (this.queuedScanLines > 0) {
7312 this.renderScanLine(this.lastUnrenderedLine);
7313 if (this.lastUnrenderedLine < 143) {
7314 ++this.lastUnrenderedLine;
7317 this.lastUnrenderedLine = 0;
7319 --this.queuedScanLines;
7322 GameBoyCore.prototype.incrementScanLineQueue = function () {
7323 if (this.queuedScanLines < 144) {
7324 ++this.queuedScanLines;
7328 this.midScanlineOffset = -1;
7329 if (this.lastUnrenderedLine < 143) {
7330 ++this.lastUnrenderedLine;
7333 this.lastUnrenderedLine = 0;
7337 GameBoyCore.prototype.midScanLineJIT = function () {
7339 this.renderMidScanLine();
7341 //Check for the highest priority IRQ to fire:
7342 GameBoyCore.prototype.launchIRQ = function () {
7346 //Check to see if an interrupt is enabled AND requested.
7347 if ((testbit & this.IRQLineMatched) == testbit) {
7348 this.IME = false; //Reset the interrupt enabling.
7349 this.interruptsRequested -= testbit; //Reset the interrupt request.
7350 this.IRQLineMatched = 0; //Reset the IRQ assertion.
7351 //Interrupts have a certain clock cycle length:
7353 //Set the stack pointer to the current program counter value:
7354 this.stackPointer = (this.stackPointer - 1) & 0xFFFF;
7355 this.memoryWriter[this.stackPointer](this, this.stackPointer, this.programCounter >> 8);
7356 this.stackPointer = (this.stackPointer - 1) & 0xFFFF;
7357 this.memoryWriter[this.stackPointer](this, this.stackPointer, this.programCounter & 0xFF);
7358 //Set the program counter to the interrupt's address:
7359 this.programCounter = 0x40 | (bitShift << 3);
7360 //Clock the core for mid-instruction updates:
7362 return; //We only want the highest priority interrupt.
7364 testbit = 1 << ++bitShift;
7365 } while (bitShift < 5);
7368 Check for IRQs to be fired while not in HALT:
7370 GameBoyCore.prototype.checkIRQMatching = function () {
7372 this.IRQLineMatched = this.interruptsEnabled & this.interruptsRequested & 0x1F;
7376 Handle the HALT opcode by predicting all IRQ cases correctly,
7377 then selecting the next closest IRQ firing from the prediction to
7378 clock up to. This prevents hacky looping that doesn't predict, but
7379 instead just clocks through the core update procedure by one which
7380 is very slow. Not many emulators do this because they have to cover
7381 all the IRQ prediction cases and they usually get them wrong.
7383 GameBoyCore.prototype.calculateHALTPeriod = function () {
7384 //Initialize our variables and start our prediction:
7387 var currentClocks = -1;
7390 //If the LCD is enabled, then predict the LCD IRQs enabled:
7391 if ((this.interruptsEnabled & 0x1) == 0x1) {
7392 currentClocks = ((456 * (((this.modeSTAT == 1) ? 298 : 144) - this.actualScanLine)) - this.LCDTicks) << this.doubleSpeedShifter;
7394 if ((this.interruptsEnabled & 0x2) == 0x2) {
7395 if (this.mode0TriggerSTAT) {
7396 temp_var = (this.clocksUntilMode0() - this.LCDTicks) << this.doubleSpeedShifter;
7397 if (temp_var <= currentClocks || currentClocks == -1) {
7398 currentClocks = temp_var;
7401 if (this.mode1TriggerSTAT && (this.interruptsEnabled & 0x1) == 0) {
7402 temp_var = ((456 * (((this.modeSTAT == 1) ? 298 : 144) - this.actualScanLine)) - this.LCDTicks) << this.doubleSpeedShifter;
7403 if (temp_var <= currentClocks || currentClocks == -1) {
7404 currentClocks = temp_var;
7407 if (this.mode2TriggerSTAT) {
7408 temp_var = (((this.actualScanLine >= 143) ? (456 * (154 - this.actualScanLine)) : 456) - this.LCDTicks) << this.doubleSpeedShifter;
7409 if (temp_var <= currentClocks || currentClocks == -1) {
7410 currentClocks = temp_var;
7413 if (this.LYCMatchTriggerSTAT && this.memory[0xFF45] <= 153) {
7414 temp_var = (this.clocksUntilLYCMatch() - this.LCDTicks) << this.doubleSpeedShifter;
7415 if (temp_var <= currentClocks || currentClocks == -1) {
7416 currentClocks = temp_var;
7421 if (this.TIMAEnabled && (this.interruptsEnabled & 0x4) == 0x4) {
7422 //CPU timer IRQ prediction:
7423 temp_var = ((0x100 - this.memory[0xFF05]) * this.TACClocker) - this.timerTicks;
7424 if (temp_var <= currentClocks || currentClocks == -1) {
7425 currentClocks = temp_var;
7428 if (this.serialTimer > 0 && (this.interruptsEnabled & 0x8) == 0x8) {
7429 //Serial IRQ prediction:
7430 if (this.serialTimer <= currentClocks || currentClocks == -1) {
7431 currentClocks = this.serialTimer;
7436 var currentClocks = this.remainingClocks;
7438 var maxClocks = (this.CPUCyclesTotal - this.emulatorTicks) << this.doubleSpeedShifter;
7439 if (currentClocks >= 0) {
7440 if (currentClocks <= maxClocks) {
7441 //Exit out of HALT normally:
7442 this.CPUTicks = Math.max(currentClocks, this.CPUTicks);
7443 this.updateCoreFull();
7448 //Still in HALT, clock only up to the clocks specified per iteration:
7449 this.CPUTicks = Math.max(maxClocks, this.CPUTicks);
7450 this.remainingClocks = currentClocks - this.CPUTicks;
7454 //Still in HALT, clock only up to the clocks specified per iteration:
7455 //Will stay in HALT forever (Stuck in HALT forever), but the APU and LCD are still clocked, so don't pause:
7456 this.CPUTicks += maxClocks;
7460 GameBoyCore.prototype.memoryRead = function (address) {
7461 //Act as a wrapper for reading the returns from the compiled jumps to memory.
7462 return this.memoryReader[address](this, address); //This seems to be faster than the usual if/else.
7464 GameBoyCore.prototype.memoryHighRead = function (address) {
7465 //Act as a wrapper for reading the returns from the compiled jumps to memory.
7466 return this.memoryHighReader[address](this, address); //This seems to be faster than the usual if/else.
7468 GameBoyCore.prototype.memoryReadJumpCompile = function () {
7469 //Faster in some browsers, since we are doing less conditionals overall by implementing them in advance.
7470 for (var index = 0x0000; index <= 0xFFFF; index++) {
7471 if (index < 0x4000) {
7472 this.memoryReader[index] = this.memoryReadNormal;
7474 else if (index < 0x8000) {
7475 this.memoryReader[index] = this.memoryReadROM;
7477 else if (index < 0x9800) {
7478 this.memoryReader[index] = (this.cGBC) ? this.VRAMDATAReadCGBCPU : this.VRAMDATAReadDMGCPU;
7480 else if (index < 0xA000) {
7481 this.memoryReader[index] = (this.cGBC) ? this.VRAMCHRReadCGBCPU : this.VRAMCHRReadDMGCPU;
7483 else if (index >= 0xA000 && index < 0xC000) {
7484 if ((this.numRAMBanks == 1 / 16 && index < 0xA200) || this.numRAMBanks >= 1) {
7486 this.memoryReader[index] = this.memoryReadMBC7;
7488 else if (!this.cMBC3) {
7489 this.memoryReader[index] = this.memoryReadMBC;
7493 this.memoryReader[index] = this.memoryReadMBC3;
7497 this.memoryReader[index] = this.memoryReadBAD;
7500 else if (index >= 0xC000 && index < 0xE000) {
7501 if (!this.cGBC || index < 0xD000) {
7502 this.memoryReader[index] = this.memoryReadNormal;
7505 this.memoryReader[index] = this.memoryReadGBCMemory;
7508 else if (index >= 0xE000 && index < 0xFE00) {
7509 if (!this.cGBC || index < 0xF000) {
7510 this.memoryReader[index] = this.memoryReadECHONormal;
7513 this.memoryReader[index] = this.memoryReadECHOGBCMemory;
7516 else if (index < 0xFEA0) {
7517 this.memoryReader[index] = this.memoryReadOAM;
7519 else if (this.cGBC && index >= 0xFEA0 && index < 0xFF00) {
7520 this.memoryReader[index] = this.memoryReadNormal;
7522 else if (index >= 0xFF00) {
7526 this.memoryHighReader[0] = this.memoryReader[0xFF00] = function (parentObj, address) {
7527 return 0xC0 | parentObj.memory[0xFF00]; //Top nibble returns as set.
7532 this.memoryHighReader[0x01] = this.memoryReader[0xFF01] = function (parentObj, address) {
7533 return (parentObj.memory[0xFF02] < 0x80) ? parentObj.memory[0xFF01] : 0xFF;
7539 this.memoryHighReader[0x02] = this.memoryReader[0xFF02] = function (parentObj, address) {
7540 return ((parentObj.serialTimer <= 0) ? 0x7C : 0xFC) | parentObj.memory[0xFF02];
7544 this.memoryHighReader[0x02] = this.memoryReader[0xFF02] = function (parentObj, address) {
7545 return ((parentObj.serialTimer <= 0) ? 0x7E : 0xFE) | parentObj.memory[0xFF02];
7551 this.memoryHighReader[0x04] = this.memoryReader[0xFF04] = function (parentObj, address) {
7552 parentObj.memory[0xFF04] = (parentObj.memory[0xFF04] + (parentObj.DIVTicks >> 8)) & 0xFF;
7553 parentObj.DIVTicks &= 0xFF;
7554 return parentObj.memory[0xFF04];
7559 this.memoryHighReader[0x07] = this.memoryReader[0xFF07] = function (parentObj, address) {
7560 return 0xF8 | parentObj.memory[0xFF07];
7565 this.memoryHighReader[0x0F] = this.memoryReader[0xFF0F] = function (parentObj, address) {
7566 return 0xE0 | parentObj.interruptsRequested;
7570 this.memoryHighReader[0x10] = this.memoryReader[0xFF10] = function (parentObj, address) {
7571 return 0x80 | parentObj.memory[0xFF10];
7575 this.memoryHighReader[0x11] = this.memoryReader[0xFF11] = function (parentObj, address) {
7576 return 0x3F | parentObj.memory[0xFF11];
7580 this.memoryHighReader[0x13] = this.memoryReader[0xFF13] = this.memoryReadBAD;
7583 this.memoryHighReader[0x14] = this.memoryReader[0xFF14] = function (parentObj, address) {
7584 return 0xBF | parentObj.memory[0xFF14];
7588 this.memoryHighReader[0x16] = this.memoryReader[0xFF16] = function (parentObj, address) {
7589 return 0x3F | parentObj.memory[0xFF16];
7593 this.memoryHighReader[0x18] = this.memoryReader[0xFF18] = this.memoryReadBAD;
7596 this.memoryHighReader[0x19] = this.memoryReader[0xFF19] = function (parentObj, address) {
7597 return 0xBF | parentObj.memory[0xFF19];
7601 this.memoryHighReader[0x1A] = this.memoryReader[0xFF1A] = function (parentObj, address) {
7602 return 0x7F | parentObj.memory[0xFF1A];
7606 this.memoryHighReader[0x1B] = this.memoryReader[0xFF1B] = this.memoryReadBAD;
7609 this.memoryHighReader[0x1C] = this.memoryReader[0xFF1C] = function (parentObj, address) {
7610 return 0x9F | parentObj.memory[0xFF1C];
7614 this.memoryHighReader[0x1D] = this.memoryReader[0xFF1D] = function (parentObj, address) {
7619 this.memoryHighReader[0x1E] = this.memoryReader[0xFF1E] = function (parentObj, address) {
7620 return 0xBF | parentObj.memory[0xFF1E];
7625 this.memoryHighReader[index & 0xFF] = this.memoryReader[index] = this.memoryReadBAD;
7628 this.memoryHighReader[0x23] = this.memoryReader[0xFF23] = function (parentObj, address) {
7629 return 0xBF | parentObj.memory[0xFF23];
7633 this.memoryHighReader[0x26] = this.memoryReader[0xFF26] = function (parentObj, address) {
7634 parentObj.audioJIT();
7635 return 0x70 | parentObj.memory[0xFF26];
7647 this.memoryHighReader[index & 0xFF] = this.memoryReader[index] = this.memoryReadBAD;
7665 this.memoryReader[index] = function (parentObj, address) {
7666 return (parentObj.channel3canPlay) ? parentObj.memory[0xFF00 | (parentObj.channel3lastSampleLookup >> 1)] : parentObj.memory[address];
7668 this.memoryHighReader[index & 0xFF] = function (parentObj, address) {
7669 return (parentObj.channel3canPlay) ? parentObj.memory[0xFF00 | (parentObj.channel3lastSampleLookup >> 1)] : parentObj.memory[0xFF00 | address];
7673 this.memoryHighReader[0x41] = this.memoryReader[0xFF41] = function (parentObj, address) {
7674 return 0x80 | parentObj.memory[0xFF41] | parentObj.modeSTAT;
7678 this.memoryHighReader[0x42] = this.memoryReader[0xFF42] = function (parentObj, address) {
7679 return parentObj.backgroundY;
7683 this.memoryHighReader[0x43] = this.memoryReader[0xFF43] = function (parentObj, address) {
7684 return parentObj.backgroundX;
7688 this.memoryHighReader[0x44] = this.memoryReader[0xFF44] = function (parentObj, address) {
7689 return ((parentObj.LCDisOn) ? parentObj.memory[0xFF44] : 0);
7694 this.memoryHighReader[0x4A] = this.memoryReader[0xFF4A] = function (parentObj, address) {
7695 return parentObj.windowY;
7699 this.memoryHighReader[0x4F] = this.memoryReader[0xFF4F] = function (parentObj, address) {
7700 return parentObj.currVRAMBank;
7705 this.memoryHighReader[0x55] = this.memoryReader[0xFF55] = function (parentObj, address) {
7706 if (!parentObj.LCDisOn && parentObj.hdmaRunning) { //Undocumented behavior alert: HDMA becomes GDMA when LCD is off (Worms Armageddon Fix).
7708 parentObj.DMAWrite((parentObj.memory[0xFF55] & 0x7F) + 1);
7709 parentObj.memory[0xFF55] = 0xFF; //Transfer completed.
7710 parentObj.hdmaRunning = false;
7712 return parentObj.memory[0xFF55];
7716 this.memoryReader[0xFF55] = this.memoryReadNormal;
7717 this.memoryHighReader[0x55] = this.memoryHighReadNormal;
7722 this.memoryHighReader[0x56] = this.memoryReader[0xFF56] = function (parentObj, address) {
7723 //Return IR "not connected" status:
7724 return 0x3C | ((parentObj.memory[0xFF56] >= 0xC0) ? (0x2 | (parentObj.memory[0xFF56] & 0xC1)) : (parentObj.memory[0xFF56] & 0xC3));
7728 this.memoryReader[0xFF56] = this.memoryReadNormal;
7729 this.memoryHighReader[0x56] = this.memoryHighReadNormal;
7734 this.memoryHighReader[0x6C] = this.memoryReader[0xFF6C] = function (parentObj, address) {
7735 return 0xFE | parentObj.memory[0xFF6C];
7739 this.memoryHighReader[0x6C] = this.memoryReader[0xFF6C] = this.memoryReadBAD;
7745 this.memoryHighReader[0x70] = this.memoryReader[0xFF70] = function (parentObj, address) {
7746 return 0x40 | parentObj.memory[0xFF70];
7750 this.memoryHighReader[0x70] = this.memoryReader[0xFF70] = this.memoryReadBAD;
7754 this.memoryHighReader[0x75] = this.memoryReader[0xFF75] = function (parentObj, address) {
7755 return 0x8F | parentObj.memory[0xFF75];
7760 this.memoryHighReader[index & 0xFF] = this.memoryReader[index] = function (parentObj, address) {
7766 this.memoryHighReader[0xFF] = this.memoryReader[0xFFFF] = function (parentObj, address) {
7767 return parentObj.interruptsEnabled;
7771 this.memoryReader[index] = this.memoryReadNormal;
7772 this.memoryHighReader[index & 0xFF] = this.memoryHighReadNormal;
7776 this.memoryReader[index] = this.memoryReadBAD;
7780 GameBoyCore.prototype.memoryReadNormal = function (parentObj, address) {
7781 return parentObj.memory[address];
7783 GameBoyCore.prototype.memoryHighReadNormal = function (parentObj, address) {
7784 return parentObj.memory[0xFF00 | address];
7786 GameBoyCore.prototype.memoryReadROM = function (parentObj, address) {
7787 return parentObj.ROM[parentObj.currentROMBank + address];
7789 GameBoyCore.prototype.memoryReadMBC = function (parentObj, address) {
7791 if (parentObj.MBCRAMBanksEnabled || settings[10]) {
7792 return parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition];
7794 //cout("Reading from disabled RAM.", 1);
7797 GameBoyCore.prototype.memoryReadMBC7 = function (parentObj, address) {
7799 if (parentObj.MBCRAMBanksEnabled || settings[10]) {
7806 //TODO: Gyro Control Register
7810 return parentObj.highY;
7813 return parentObj.lowY;
7816 return parentObj.highX;
7819 return parentObj.lowX;
7821 return parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition];
7824 //cout("Reading from disabled RAM.", 1);
7827 GameBoyCore.prototype.memoryReadMBC3 = function (parentObj, address) {
7829 if (parentObj.MBCRAMBanksEnabled || settings[10]) {
7830 switch (parentObj.currMBCRAMBank) {
7835 return parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition];
7838 return parentObj.latchedSeconds;
7841 return parentObj.latchedMinutes;
7844 return parentObj.latchedHours;
7847 return parentObj.latchedLDays;
7850 return (((parentObj.RTCDayOverFlow) ? 0x80 : 0) + ((parentObj.RTCHALT) ? 0x40 : 0)) + parentObj.latchedHDays;
7853 //cout("Reading from invalid or disabled RAM.", 1);
7856 GameBoyCore.prototype.memoryReadGBCMemory = function (parentObj, address) {
7857 return parentObj.GBCMemory[address + parentObj.gbcRamBankPosition];
7859 GameBoyCore.prototype.memoryReadOAM = function (parentObj, address) {
7860 return (parentObj.modeSTAT > 1) ? 0xFF : parentObj.memory[address];
7862 GameBoyCore.prototype.memoryReadECHOGBCMemory = function (parentObj, address) {
7863 return parentObj.GBCMemory[address + parentObj.gbcRamBankPositionECHO];
7865 GameBoyCore.prototype.memoryReadECHONormal = function (parentObj, address) {
7866 return parentObj.memory[address - 0x2000];
7868 GameBoyCore.prototype.memoryReadBAD = function (parentObj, address) {
7871 GameBoyCore.prototype.VRAMDATAReadCGBCPU = function (parentObj, address) {
7872 //CPU Side Reading The VRAM (Optimized for GameBoy Color)
7873 return (parentObj.modeSTAT > 2) ? 0xFF : ((parentObj.currVRAMBank == 0) ? parentObj.memory[address] : parentObj.VRAM[address & 0x1FFF]);
7875 GameBoyCore.prototype.VRAMDATAReadDMGCPU = function (parentObj, address) {
7876 //CPU Side Reading The VRAM (Optimized for classic GameBoy)
7877 return (parentObj.modeSTAT > 2) ? 0xFF : parentObj.memory[address];
7879 GameBoyCore.prototype.VRAMCHRReadCGBCPU = function (parentObj, address) {
7880 //CPU Side Reading the Character Data Map:
7881 return (parentObj.modeSTAT > 2) ? 0xFF : parentObj.BGCHRCurrentBank[address & 0x7FF];
7883 GameBoyCore.prototype.VRAMCHRReadDMGCPU = function (parentObj, address) {
7884 //CPU Side Reading the Character Data Map:
7885 return (parentObj.modeSTAT > 2) ? 0xFF : parentObj.BGCHRBank1[address & 0x7FF];
7887 GameBoyCore.prototype.setCurrentMBC1ROMBank = function () {
7888 //Read the cartridge ROM data from RAM memory:
7889 switch (this.ROMBank1offs) {
7894 //Bank calls for 0x00, 0x20, 0x40, and 0x60 are really for 0x01, 0x21, 0x41, and 0x61.
7895 this.currentROMBank = (this.ROMBank1offs % this.ROMBankEdge) << 14;
7898 this.currentROMBank = ((this.ROMBank1offs % this.ROMBankEdge) - 1) << 14;
7901 GameBoyCore.prototype.setCurrentMBC2AND3ROMBank = function () {
7902 //Read the cartridge ROM data from RAM memory:
7903 //Only map bank 0 to bank 1 here (MBC2 is like MBC1, but can only do 16 banks, so only the bank 0 quirk appears for MBC2):
7904 this.currentROMBank = Math.max((this.ROMBank1offs % this.ROMBankEdge) - 1, 0) << 14;
7906 GameBoyCore.prototype.setCurrentMBC5ROMBank = function () {
7907 //Read the cartridge ROM data from RAM memory:
7908 this.currentROMBank = ((this.ROMBank1offs % this.ROMBankEdge) - 1) << 14;
7911 GameBoyCore.prototype.memoryWrite = function (address, data) {
7912 //Act as a wrapper for writing by compiled jumps to specific memory writing functions.
7913 this.memoryWriter[address](this, address, data);
7916 GameBoyCore.prototype.memoryHighWrite = function (address, data) {
7917 //Act as a wrapper for writing by compiled jumps to specific memory writing functions.
7918 this.memoryHighWriter[address](this, address, data);
7920 GameBoyCore.prototype.memoryWriteJumpCompile = function () {
7921 //Faster in some browsers, since we are doing less conditionals overall by implementing them in advance.
7922 for (var index = 0x0000; index <= 0xFFFF; index++) {
7923 if (index < 0x8000) {
7925 if (index < 0x2000) {
7926 this.memoryWriter[index] = this.MBCWriteEnable;
7928 else if (index < 0x4000) {
7929 this.memoryWriter[index] = this.MBC1WriteROMBank;
7931 else if (index < 0x6000) {
7932 this.memoryWriter[index] = this.MBC1WriteRAMBank;
7935 this.memoryWriter[index] = this.MBC1WriteType;
7938 else if (this.cMBC2) {
7939 if (index < 0x1000) {
7940 this.memoryWriter[index] = this.MBCWriteEnable;
7942 else if (index >= 0x2100 && index < 0x2200) {
7943 this.memoryWriter[index] = this.MBC2WriteROMBank;
7946 this.memoryWriter[index] = this.cartIgnoreWrite;
7949 else if (this.cMBC3) {
7950 if (index < 0x2000) {
7951 this.memoryWriter[index] = this.MBCWriteEnable;
7953 else if (index < 0x4000) {
7954 this.memoryWriter[index] = this.MBC3WriteROMBank;
7956 else if (index < 0x6000) {
7957 this.memoryWriter[index] = this.MBC3WriteRAMBank;
7960 this.memoryWriter[index] = this.MBC3WriteRTCLatch;
7963 else if (this.cMBC5 || this.cRUMBLE || this.cMBC7) {
7964 if (index < 0x2000) {
7965 this.memoryWriter[index] = this.MBCWriteEnable;
7967 else if (index < 0x3000) {
7968 this.memoryWriter[index] = this.MBC5WriteROMBankLow;
7970 else if (index < 0x4000) {
7971 this.memoryWriter[index] = this.MBC5WriteROMBankHigh;
7973 else if (index < 0x6000) {
7974 this.memoryWriter[index] = (this.cRUMBLE) ? this.RUMBLEWriteRAMBank : this.MBC5WriteRAMBank;
7977 this.memoryWriter[index] = this.cartIgnoreWrite;
7980 else if (this.cHuC3) {
7981 if (index < 0x2000) {
7982 this.memoryWriter[index] = this.MBCWriteEnable;
7984 else if (index < 0x4000) {
7985 this.memoryWriter[index] = this.MBC3WriteROMBank;
7987 else if (index < 0x6000) {
7988 this.memoryWriter[index] = this.HuC3WriteRAMBank;
7991 this.memoryWriter[index] = this.cartIgnoreWrite;
7995 this.memoryWriter[index] = this.cartIgnoreWrite;
7998 else if (index < 0x9000) {
7999 this.memoryWriter[index] = (this.cGBC) ? this.VRAMGBCDATAWrite : this.VRAMGBDATAWrite;
8001 else if (index < 0x9800) {
8002 this.memoryWriter[index] = (this.cGBC) ? this.VRAMGBCDATAWrite : this.VRAMGBDATAUpperWrite;
8004 else if (index < 0xA000) {
8005 this.memoryWriter[index] = (this.cGBC) ? this.VRAMGBCCHRMAPWrite : this.VRAMGBCHRMAPWrite;
8007 else if (index < 0xC000) {
8008 if ((this.numRAMBanks == 1 / 16 && index < 0xA200) || this.numRAMBanks >= 1) {
8010 this.memoryWriter[index] = this.memoryWriteMBCRAM;
8014 this.memoryWriter[index] = this.memoryWriteMBC3RAM;
8018 this.memoryWriter[index] = this.cartIgnoreWrite;
8021 else if (index < 0xE000) {
8022 if (this.cGBC && index >= 0xD000) {
8023 this.memoryWriter[index] = this.memoryWriteGBCRAM;
8026 this.memoryWriter[index] = this.memoryWriteNormal;
8029 else if (index < 0xFE00) {
8030 if (this.cGBC && index >= 0xF000) {
8031 this.memoryWriter[index] = this.memoryWriteECHOGBCRAM;
8034 this.memoryWriter[index] = this.memoryWriteECHONormal;
8037 else if (index <= 0xFEA0) {
8038 this.memoryWriter[index] = this.memoryWriteOAMRAM;
8040 else if (index < 0xFF00) {
8041 if (this.cGBC) { //Only GBC has access to this RAM.
8042 this.memoryWriter[index] = this.memoryWriteNormal;
8045 this.memoryWriter[index] = this.cartIgnoreWrite;
8049 //Start the I/O initialization by filling in the slots as normal memory:
8050 this.memoryWriter[index] = this.memoryWriteNormal;
8051 this.memoryHighWriter[index & 0xFF] = this.memoryHighWriteNormal;
8054 this.registerWriteJumpCompile(); //Compile the I/O write functions separately...
8056 GameBoyCore.prototype.MBCWriteEnable = function (parentObj, address, data) {
8057 //MBC RAM Bank Enable/Disable:
8058 parentObj.MBCRAMBanksEnabled = ((data & 0x0F) == 0x0A); //If lower nibble is 0x0A, then enable, otherwise disable.
8060 GameBoyCore.prototype.MBC1WriteROMBank = function (parentObj, address, data) {
8061 //MBC1 ROM bank switching:
8062 parentObj.ROMBank1offs = (parentObj.ROMBank1offs & 0x60) | (data & 0x1F);
8063 parentObj.setCurrentMBC1ROMBank();
8065 GameBoyCore.prototype.MBC1WriteRAMBank = function (parentObj, address, data) {
8066 //MBC1 RAM bank switching
8067 if (parentObj.MBC1Mode) {
8069 parentObj.currMBCRAMBank = data & 0x03;
8070 parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
8074 parentObj.ROMBank1offs = ((data & 0x03) << 5) | (parentObj.ROMBank1offs & 0x1F);
8075 parentObj.setCurrentMBC1ROMBank();
8078 GameBoyCore.prototype.MBC1WriteType = function (parentObj, address, data) {
8079 //MBC1 mode setting:
8080 parentObj.MBC1Mode = ((data & 0x1) == 0x1);
8081 if (parentObj.MBC1Mode) {
8082 parentObj.ROMBank1offs &= 0x1F;
8083 parentObj.setCurrentMBC1ROMBank();
8086 parentObj.currMBCRAMBank = 0;
8087 parentObj.currMBCRAMBankPosition = -0xA000;
8090 GameBoyCore.prototype.MBC2WriteROMBank = function (parentObj, address, data) {
8091 //MBC2 ROM bank switching:
8092 parentObj.ROMBank1offs = data & 0x0F;
8093 parentObj.setCurrentMBC2AND3ROMBank();
8095 GameBoyCore.prototype.MBC3WriteROMBank = function (parentObj, address, data) {
8096 //MBC3 ROM bank switching:
8097 parentObj.ROMBank1offs = data & 0x7F;
8098 parentObj.setCurrentMBC2AND3ROMBank();
8100 GameBoyCore.prototype.MBC3WriteRAMBank = function (parentObj, address, data) {
8101 parentObj.currMBCRAMBank = data;
8103 //MBC3 RAM bank switching
8104 parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
8107 GameBoyCore.prototype.MBC3WriteRTCLatch = function (parentObj, address, data) {
8109 parentObj.RTCisLatched = false;
8111 else if (!parentObj.RTCisLatched) {
8112 //Copy over the current RTC time for reading.
8113 parentObj.RTCisLatched = true;
8114 parentObj.latchedSeconds = parentObj.RTCSeconds | 0;
8115 parentObj.latchedMinutes = parentObj.RTCMinutes;
8116 parentObj.latchedHours = parentObj.RTCHours;
8117 parentObj.latchedLDays = (parentObj.RTCDays & 0xFF);
8118 parentObj.latchedHDays = parentObj.RTCDays >> 8;
8121 GameBoyCore.prototype.MBC5WriteROMBankLow = function (parentObj, address, data) {
8122 //MBC5 ROM bank switching:
8123 parentObj.ROMBank1offs = (parentObj.ROMBank1offs & 0x100) | data;
8124 parentObj.setCurrentMBC5ROMBank();
8126 GameBoyCore.prototype.MBC5WriteROMBankHigh = function (parentObj, address, data) {
8127 //MBC5 ROM bank switching (by least significant bit):
8128 parentObj.ROMBank1offs = ((data & 0x01) << 8) | (parentObj.ROMBank1offs & 0xFF);
8129 parentObj.setCurrentMBC5ROMBank();
8131 GameBoyCore.prototype.MBC5WriteRAMBank = function (parentObj, address, data) {
8132 //MBC5 RAM bank switching
8133 parentObj.currMBCRAMBank = data & 0xF;
8134 parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
8136 GameBoyCore.prototype.RUMBLEWriteRAMBank = function (parentObj, address, data) {
8137 //MBC5 RAM bank switching
8138 //Like MBC5, but bit 3 of the lower nibble is used for rumbling and bit 2 is ignored.
8139 parentObj.currMBCRAMBank = data & 0x03;
8140 parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
8142 GameBoyCore.prototype.HuC3WriteRAMBank = function (parentObj, address, data) {
8143 //HuC3 RAM bank switching
8144 parentObj.currMBCRAMBank = data & 0x03;
8145 parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
8147 GameBoyCore.prototype.cartIgnoreWrite = function (parentObj, address, data) {
8148 //We might have encountered illegal RAM writing or such, so just do nothing...
8150 GameBoyCore.prototype.memoryWriteNormal = function (parentObj, address, data) {
8151 parentObj.memory[address] = data;
8153 GameBoyCore.prototype.memoryHighWriteNormal = function (parentObj, address, data) {
8154 parentObj.memory[0xFF00 | address] = data;
8156 GameBoyCore.prototype.memoryWriteMBCRAM = function (parentObj, address, data) {
8157 if (parentObj.MBCRAMBanksEnabled || settings[10]) {
8158 parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition] = data;
8161 GameBoyCore.prototype.memoryWriteMBC3RAM = function (parentObj, address, data) {
8162 if (parentObj.MBCRAMBanksEnabled || settings[10]) {
8163 switch (parentObj.currMBCRAMBank) {
8168 parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition] = data;
8172 parentObj.RTCSeconds = data;
8175 cout("(Bank #" + parentObj.currMBCRAMBank + ") RTC write out of range: " + data, 1);
8180 parentObj.RTCMinutes = data;
8183 cout("(Bank #" + parentObj.currMBCRAMBank + ") RTC write out of range: " + data, 1);
8188 parentObj.RTCHours = data;
8191 cout("(Bank #" + parentObj.currMBCRAMBank + ") RTC write out of range: " + data, 1);
8195 parentObj.RTCDays = (data & 0xFF) | (parentObj.RTCDays & 0x100);
8198 parentObj.RTCDayOverFlow = (data > 0x7F);
8199 parentObj.RTCHalt = (data & 0x40) == 0x40;
8200 parentObj.RTCDays = ((data & 0x1) << 8) | (parentObj.RTCDays & 0xFF);
8203 cout("Invalid MBC3 bank address selected: " + parentObj.currMBCRAMBank, 0);
8207 GameBoyCore.prototype.memoryWriteGBCRAM = function (parentObj, address, data) {
8208 parentObj.GBCMemory[address + parentObj.gbcRamBankPosition] = data;
8210 GameBoyCore.prototype.memoryWriteOAMRAM = function (parentObj, address, data) {
8211 if (parentObj.modeSTAT < 2) { //OAM RAM cannot be written to in mode 2 & 3
8212 if (parentObj.memory[address] != data) {
8213 parentObj.graphicsJIT();
8214 parentObj.memory[address] = data;
8218 GameBoyCore.prototype.memoryWriteECHOGBCRAM = function (parentObj, address, data) {
8219 parentObj.GBCMemory[address + parentObj.gbcRamBankPositionECHO] = data;
8221 GameBoyCore.prototype.memoryWriteECHONormal = function (parentObj, address, data) {
8222 parentObj.memory[address - 0x2000] = data;
8224 GameBoyCore.prototype.VRAMGBDATAWrite = function (parentObj, address, data) {
8225 if (parentObj.modeSTAT < 3) { //VRAM cannot be written to during mode 3
8226 if (parentObj.memory[address] != data) {
8227 //JIT the graphics render queue:
8228 parentObj.graphicsJIT();
8229 parentObj.memory[address] = data;
8230 parentObj.generateGBOAMTileLine(address);
8234 GameBoyCore.prototype.VRAMGBDATAUpperWrite = function (parentObj, address, data) {
8235 if (parentObj.modeSTAT < 3) { //VRAM cannot be written to during mode 3
8236 if (parentObj.memory[address] != data) {
8237 //JIT the graphics render queue:
8238 parentObj.graphicsJIT();
8239 parentObj.memory[address] = data;
8240 parentObj.generateGBTileLine(address);
8244 GameBoyCore.prototype.VRAMGBCDATAWrite = function (parentObj, address, data) {
8245 if (parentObj.modeSTAT < 3) { //VRAM cannot be written to during mode 3
8246 if (parentObj.currVRAMBank == 0) {
8247 if (parentObj.memory[address] != data) {
8248 //JIT the graphics render queue:
8249 parentObj.graphicsJIT();
8250 parentObj.memory[address] = data;
8251 parentObj.generateGBCTileLineBank1(address);
8256 if (parentObj.VRAM[address] != data) {
8257 //JIT the graphics render queue:
8258 parentObj.graphicsJIT();
8259 parentObj.VRAM[address] = data;
8260 parentObj.generateGBCTileLineBank2(address);
8265 GameBoyCore.prototype.VRAMGBCHRMAPWrite = function (parentObj, address, data) {
8266 if (parentObj.modeSTAT < 3) { //VRAM cannot be written to during mode 3
8268 if (parentObj.BGCHRBank1[address] != data) {
8269 //JIT the graphics render queue:
8270 parentObj.graphicsJIT();
8271 parentObj.BGCHRBank1[address] = data;
8275 GameBoyCore.prototype.VRAMGBCCHRMAPWrite = function (parentObj, address, data) {
8276 if (parentObj.modeSTAT < 3) { //VRAM cannot be written to during mode 3
8278 if (parentObj.BGCHRCurrentBank[address] != data) {
8279 //JIT the graphics render queue:
8280 parentObj.graphicsJIT();
8281 parentObj.BGCHRCurrentBank[address] = data;
8285 GameBoyCore.prototype.DMAWrite = function (tilesToTransfer) {
8287 //Clock the CPU for the DMA transfer (CPU is halted during the transfer):
8288 this.CPUTicks += 4 | ((tilesToTransfer << 5) << this.doubleSpeedShifter);
8290 //Source address of the transfer:
8291 var source = (this.memory[0xFF51] << 8) | this.memory[0xFF52];
8292 //Destination address in the VRAM memory range:
8293 var destination = (this.memory[0xFF53] << 8) | this.memory[0xFF54];
8294 //Creating some references:
8295 var memoryReader = this.memoryReader;
8296 //JIT the graphics render queue:
8298 var memory = this.memory;
8299 //Determining which bank we're working on so we can optimize:
8300 if (this.currVRAMBank == 0) {
8301 //DMA transfer for VRAM bank 0:
8303 if (destination < 0x1800) {
8304 memory[0x8000 | destination] = memoryReader[source](this, source++);
8305 memory[0x8001 | destination] = memoryReader[source](this, source++);
8306 memory[0x8002 | destination] = memoryReader[source](this, source++);
8307 memory[0x8003 | destination] = memoryReader[source](this, source++);
8308 memory[0x8004 | destination] = memoryReader[source](this, source++);
8309 memory[0x8005 | destination] = memoryReader[source](this, source++);
8310 memory[0x8006 | destination] = memoryReader[source](this, source++);
8311 memory[0x8007 | destination] = memoryReader[source](this, source++);
8312 memory[0x8008 | destination] = memoryReader[source](this, source++);
8313 memory[0x8009 | destination] = memoryReader[source](this, source++);
8314 memory[0x800A | destination] = memoryReader[source](this, source++);
8315 memory[0x800B | destination] = memoryReader[source](this, source++);
8316 memory[0x800C | destination] = memoryReader[source](this, source++);
8317 memory[0x800D | destination] = memoryReader[source](this, source++);
8318 memory[0x800E | destination] = memoryReader[source](this, source++);
8319 memory[0x800F | destination] = memoryReader[source](this, source++);
8320 this.generateGBCTileBank1(destination);
8321 destination += 0x10;
8324 destination &= 0x7F0;
8325 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8326 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8327 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8328 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8329 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8330 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8331 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8332 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8333 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8334 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8335 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8336 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8337 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8338 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8339 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8340 this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
8341 destination = (destination + 0x1800) & 0x1FF0;
8345 } while (tilesToTransfer > 0);
8348 var VRAM = this.VRAM;
8349 //DMA transfer for VRAM bank 1:
8351 if (destination < 0x1800) {
8352 VRAM[destination] = memoryReader[source](this, source++);
8353 VRAM[destination | 0x1] = memoryReader[source](this, source++);
8354 VRAM[destination | 0x2] = memoryReader[source](this, source++);
8355 VRAM[destination | 0x3] = memoryReader[source](this, source++);
8356 VRAM[destination | 0x4] = memoryReader[source](this, source++);
8357 VRAM[destination | 0x5] = memoryReader[source](this, source++);
8358 VRAM[destination | 0x6] = memoryReader[source](this, source++);
8359 VRAM[destination | 0x7] = memoryReader[source](this, source++);
8360 VRAM[destination | 0x8] = memoryReader[source](this, source++);
8361 VRAM[destination | 0x9] = memoryReader[source](this, source++);
8362 VRAM[destination | 0xA] = memoryReader[source](this, source++);
8363 VRAM[destination | 0xB] = memoryReader[source](this, source++);
8364 VRAM[destination | 0xC] = memoryReader[source](this, source++);
8365 VRAM[destination | 0xD] = memoryReader[source](this, source++);
8366 VRAM[destination | 0xE] = memoryReader[source](this, source++);
8367 VRAM[destination | 0xF] = memoryReader[source](this, source++);
8368 this.generateGBCTileBank2(destination);
8369 destination += 0x10;
8372 destination &= 0x7F0;
8373 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8374 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8375 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8376 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8377 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8378 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8379 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8380 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8381 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8382 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8383 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8384 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8385 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8386 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8387 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8388 this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
8389 destination = (destination + 0x1800) & 0x1FF0;
8393 } while (tilesToTransfer > 0);
8395 //Update the HDMA registers to their next addresses:
8396 memory[0xFF51] = source >> 8;
8397 memory[0xFF52] = source & 0xF0;
8398 memory[0xFF53] = destination >> 8;
8399 memory[0xFF54] = destination & 0xF0;
8401 GameBoyCore.prototype.registerWriteJumpCompile = function () {
8402 //I/O Registers (GB + GBC):
8404 this.memoryHighWriter[0] = this.memoryWriter[0xFF00] = function (parentObj, address, data) {
8405 parentObj.memory[0xFF00] = (data & 0x30) | ((((data & 0x20) == 0) ? (parentObj.JoyPad >> 4) : 0xF) & (((data & 0x10) == 0) ? (parentObj.JoyPad & 0xF) : 0xF));
8407 //SB (Serial Transfer Data)
8408 this.memoryHighWriter[0x1] = this.memoryWriter[0xFF01] = function (parentObj, address, data) {
8409 if (parentObj.memory[0xFF02] < 0x80) { //Cannot write while a serial transfer is active.
8410 parentObj.memory[0xFF01] = data;
8414 this.memoryHighWriter[0x4] = this.memoryWriter[0xFF04] = function (parentObj, address, data) {
8415 parentObj.DIVTicks &= 0xFF; //Update DIV for realignment.
8416 parentObj.memory[0xFF04] = 0;
8419 this.memoryHighWriter[0x5] = this.memoryWriter[0xFF05] = function (parentObj, address, data) {
8420 parentObj.memory[0xFF05] = data;
8423 this.memoryHighWriter[0x6] = this.memoryWriter[0xFF06] = function (parentObj, address, data) {
8424 parentObj.memory[0xFF06] = data;
8427 this.memoryHighWriter[0x7] = this.memoryWriter[0xFF07] = function (parentObj, address, data) {
8428 parentObj.memory[0xFF07] = data & 0x07;
8429 parentObj.TIMAEnabled = (data & 0x04) == 0x04;
8430 parentObj.TACClocker = Math.pow(4, ((data & 0x3) != 0) ? (data & 0x3) : 4) << 2; //TODO: Find a way to not make a conditional in here...
8432 //IF (Interrupt Request)
8433 this.memoryHighWriter[0xF] = this.memoryWriter[0xFF0F] = function (parentObj, address, data) {
8434 parentObj.interruptsRequested = data;
8435 parentObj.checkIRQMatching();
8437 this.memoryHighWriter[0x10] = this.memoryWriter[0xFF10] = function (parentObj, address, data) {
8438 if (parentObj.soundMasterEnabled) {
8439 parentObj.audioJIT();
8440 if (parentObj.channel1decreaseSweep && (data & 0x08) == 0) {
8441 if (parentObj.channel1numSweep != parentObj.channel1frequencySweepDivider) {
8442 parentObj.channel1SweepFault = true;
8445 parentObj.channel1lastTimeSweep = (data & 0x70) >> 4;
8446 parentObj.channel1frequencySweepDivider = data & 0x07;
8447 parentObj.channel1decreaseSweep = ((data & 0x08) == 0x08);
8448 parentObj.memory[0xFF10] = data;
8449 parentObj.channel1EnableCheck();
8452 this.memoryHighWriter[0x11] = this.memoryWriter[0xFF11] = function (parentObj, address, data) {
8453 if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
8454 if (parentObj.soundMasterEnabled) {
8455 parentObj.audioJIT();
8460 parentObj.channel1CachedDuty = parentObj.dutyLookup[data >> 6];
8461 parentObj.channel1totalLength = 0x40 - (data & 0x3F);
8462 parentObj.memory[0xFF11] = data & 0xC0;
8463 parentObj.channel1EnableCheck();
8466 this.memoryHighWriter[0x12] = this.memoryWriter[0xFF12] = function (parentObj, address, data) {
8467 if (parentObj.soundMasterEnabled) {
8468 parentObj.audioJIT();
8469 if (parentObj.channel1Enabled && parentObj.channel1envelopeSweeps == 0) {
8470 //Zombie Volume PAPU Bug:
8471 if (((parentObj.memory[0xFF12] ^ data) & 0x8) == 0x8) {
8472 if ((parentObj.memory[0xFF12] & 0x8) == 0) {
8473 if ((parentObj.memory[0xFF12] & 0x7) == 0x7) {
8474 parentObj.channel1envelopeVolume += 2;
8477 ++parentObj.channel1envelopeVolume;
8480 parentObj.channel1envelopeVolume = (16 - parentObj.channel1envelopeVolume) & 0xF;
8482 else if ((parentObj.memory[0xFF12] & 0xF) == 0x8) {
8483 parentObj.channel1envelopeVolume = (1 + parentObj.channel1envelopeVolume) & 0xF;
8485 parentObj.channel1OutputLevelCache();
8487 parentObj.channel1envelopeType = ((data & 0x08) == 0x08);
8488 parentObj.memory[0xFF12] = data;
8489 parentObj.channel1VolumeEnableCheck();
8492 this.memoryHighWriter[0x13] = this.memoryWriter[0xFF13] = function (parentObj, address, data) {
8493 if (parentObj.soundMasterEnabled) {
8494 parentObj.audioJIT();
8495 parentObj.channel1frequency = (parentObj.channel1frequency & 0x700) | data;
8496 parentObj.channel1FrequencyTracker = (0x800 - parentObj.channel1frequency) << 2;
8497 parentObj.memory[0xFF13] = data;
8500 this.memoryHighWriter[0x14] = this.memoryWriter[0xFF14] = function (parentObj, address, data) {
8501 if (parentObj.soundMasterEnabled) {
8502 parentObj.audioJIT();
8503 parentObj.channel1consecutive = ((data & 0x40) == 0x0);
8504 parentObj.channel1frequency = ((data & 0x7) << 8) | (parentObj.channel1frequency & 0xFF);
8505 parentObj.channel1FrequencyTracker = (0x800 - parentObj.channel1frequency) << 2;
8508 parentObj.channel1timeSweep = parentObj.channel1lastTimeSweep;
8509 parentObj.channel1numSweep = parentObj.channel1frequencySweepDivider;
8511 var nr12 = parentObj.memory[0xFF12];
8512 parentObj.channel1envelopeVolume = nr12 >> 4;
8513 parentObj.channel1OutputLevelCache();
8514 parentObj.channel1envelopeSweepsLast = (nr12 & 0x7) - 1;
8515 if (parentObj.channel1totalLength == 0) {
8516 parentObj.channel1totalLength = 0x40;
8518 if (parentObj.channel1lastTimeSweep > 0 || parentObj.channel1frequencySweepDivider > 0) {
8519 parentObj.memory[0xFF26] |= 0x1;
8522 parentObj.memory[0xFF26] &= 0xFE;
8524 if ((data & 0x40) == 0x40) {
8525 parentObj.memory[0xFF26] |= 0x1;
8527 parentObj.channel1ShadowFrequency = parentObj.channel1frequency;
8528 //Reset frequency overflow check + frequency sweep type check:
8529 parentObj.channel1SweepFault = false;
8530 //Supposed to run immediately:
8531 parentObj.runAudioSweep();
8533 parentObj.channel1EnableCheck();
8534 parentObj.memory[0xFF14] = data & 0x40;
8537 this.memoryHighWriter[0x16] = this.memoryWriter[0xFF16] = function (parentObj, address, data) {
8538 if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
8539 if (parentObj.soundMasterEnabled) {
8540 parentObj.audioJIT();
8545 parentObj.channel2CachedDuty = parentObj.dutyLookup[data >> 6];
8546 parentObj.channel2totalLength = 0x40 - (data & 0x3F);
8547 parentObj.memory[0xFF16] = data & 0xC0;
8548 parentObj.channel2EnableCheck();
8551 this.memoryHighWriter[0x17] = this.memoryWriter[0xFF17] = function (parentObj, address, data) {
8552 if (parentObj.soundMasterEnabled) {
8553 parentObj.audioJIT();
8554 if (parentObj.channel2Enabled && parentObj.channel2envelopeSweeps == 0) {
8555 //Zombie Volume PAPU Bug:
8556 if (((parentObj.memory[0xFF17] ^ data) & 0x8) == 0x8) {
8557 if ((parentObj.memory[0xFF17] & 0x8) == 0) {
8558 if ((parentObj.memory[0xFF17] & 0x7) == 0x7) {
8559 parentObj.channel2envelopeVolume += 2;
8562 ++parentObj.channel2envelopeVolume;
8565 parentObj.channel2envelopeVolume = (16 - parentObj.channel2envelopeVolume) & 0xF;
8567 else if ((parentObj.memory[0xFF17] & 0xF) == 0x8) {
8568 parentObj.channel2envelopeVolume = (1 + parentObj.channel2envelopeVolume) & 0xF;
8570 parentObj.channel2OutputLevelCache();
8572 parentObj.channel2envelopeType = ((data & 0x08) == 0x08);
8573 parentObj.memory[0xFF17] = data;
8574 parentObj.channel2VolumeEnableCheck();
8577 this.memoryHighWriter[0x18] = this.memoryWriter[0xFF18] = function (parentObj, address, data) {
8578 if (parentObj.soundMasterEnabled) {
8579 parentObj.audioJIT();
8580 parentObj.channel2frequency = (parentObj.channel2frequency & 0x700) | data;
8581 parentObj.channel2FrequencyTracker = (0x800 - parentObj.channel2frequency) << 2;
8582 parentObj.memory[0xFF18] = data;
8585 this.memoryHighWriter[0x19] = this.memoryWriter[0xFF19] = function (parentObj, address, data) {
8586 if (parentObj.soundMasterEnabled) {
8587 parentObj.audioJIT();
8590 var nr22 = parentObj.memory[0xFF17];
8591 parentObj.channel2envelopeVolume = nr22 >> 4;
8592 parentObj.channel2OutputLevelCache();
8593 parentObj.channel2envelopeSweepsLast = (nr22 & 0x7) - 1;
8594 if (parentObj.channel2totalLength == 0) {
8595 parentObj.channel2totalLength = 0x40;
8597 if ((data & 0x40) == 0x40) {
8598 parentObj.memory[0xFF26] |= 0x2;
8601 parentObj.channel2consecutive = ((data & 0x40) == 0x0);
8602 parentObj.channel2frequency = ((data & 0x7) << 8) | (parentObj.channel2frequency & 0xFF);
8603 parentObj.channel2FrequencyTracker = (0x800 - parentObj.channel2frequency) << 2;
8604 parentObj.memory[0xFF19] = data & 0x40;
8605 parentObj.channel2EnableCheck();
8608 this.memoryHighWriter[0x1A] = this.memoryWriter[0xFF1A] = function (parentObj, address, data) {
8609 if (parentObj.soundMasterEnabled) {
8610 parentObj.audioJIT();
8611 if (!parentObj.channel3canPlay && data >= 0x80) {
8612 parentObj.channel3lastSampleLookup = 0;
8613 parentObj.channel3UpdateCache();
8615 parentObj.channel3canPlay = (data > 0x7F);
8616 if (parentObj.channel3canPlay && parentObj.memory[0xFF1A] > 0x7F && !parentObj.channel3consecutive) {
8617 parentObj.memory[0xFF26] |= 0x4;
8619 parentObj.memory[0xFF1A] = data & 0x80;
8620 //parentObj.channel3EnableCheck();
8623 this.memoryHighWriter[0x1B] = this.memoryWriter[0xFF1B] = function (parentObj, address, data) {
8624 if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
8625 if (parentObj.soundMasterEnabled) {
8626 parentObj.audioJIT();
8628 parentObj.channel3totalLength = 0x100 - data;
8629 parentObj.memory[0xFF1B] = data;
8630 parentObj.channel3EnableCheck();
8633 this.memoryHighWriter[0x1C] = this.memoryWriter[0xFF1C] = function (parentObj, address, data) {
8634 if (parentObj.soundMasterEnabled) {
8635 parentObj.audioJIT();
8637 parentObj.memory[0xFF1C] = data;
8638 parentObj.channel3patternType = (data == 0) ? 4 : ((data >> 5) - 1);
8641 this.memoryHighWriter[0x1D] = this.memoryWriter[0xFF1D] = function (parentObj, address, data) {
8642 if (parentObj.soundMasterEnabled) {
8643 parentObj.audioJIT();
8644 parentObj.channel3frequency = (parentObj.channel3frequency & 0x700) | data;
8645 parentObj.channel3FrequencyPeriod = (0x800 - parentObj.channel3frequency) << 1;
8646 parentObj.memory[0xFF1D] = data;
8649 this.memoryHighWriter[0x1E] = this.memoryWriter[0xFF1E] = function (parentObj, address, data) {
8650 if (parentObj.soundMasterEnabled) {
8651 parentObj.audioJIT();
8653 if (parentObj.channel3totalLength == 0) {
8654 parentObj.channel3totalLength = 0x100;
8656 parentObj.channel3lastSampleLookup = 0;
8657 if ((data & 0x40) == 0x40) {
8658 parentObj.memory[0xFF26] |= 0x4;
8661 parentObj.channel3consecutive = ((data & 0x40) == 0x0);
8662 parentObj.channel3frequency = ((data & 0x7) << 8) | (parentObj.channel3frequency & 0xFF);
8663 parentObj.channel3FrequencyPeriod = (0x800 - parentObj.channel3frequency) << 1;
8664 parentObj.memory[0xFF1E] = data & 0x40;
8665 parentObj.channel3EnableCheck();
8668 this.memoryHighWriter[0x20] = this.memoryWriter[0xFF20] = function (parentObj, address, data) {
8669 if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
8670 if (parentObj.soundMasterEnabled) {
8671 parentObj.audioJIT();
8673 parentObj.channel4totalLength = 0x40 - (data & 0x3F);
8674 parentObj.memory[0xFF20] = data | 0xC0;
8675 parentObj.channel4EnableCheck();
8678 this.memoryHighWriter[0x21] = this.memoryWriter[0xFF21] = function (parentObj, address, data) {
8679 if (parentObj.soundMasterEnabled) {
8680 parentObj.audioJIT();
8681 if (parentObj.channel4Enabled && parentObj.channel4envelopeSweeps == 0) {
8682 //Zombie Volume PAPU Bug:
8683 if (((parentObj.memory[0xFF21] ^ data) & 0x8) == 0x8) {
8684 if ((parentObj.memory[0xFF21] & 0x8) == 0) {
8685 if ((parentObj.memory[0xFF21] & 0x7) == 0x7) {
8686 parentObj.channel4envelopeVolume += 2;
8689 ++parentObj.channel4envelopeVolume;
8692 parentObj.channel4envelopeVolume = (16 - parentObj.channel4envelopeVolume) & 0xF;
8694 else if ((parentObj.memory[0xFF21] & 0xF) == 0x8) {
8695 parentObj.channel4envelopeVolume = (1 + parentObj.channel4envelopeVolume) & 0xF;
8697 parentObj.channel4currentVolume = parentObj.channel4envelopeVolume << parentObj.channel4VolumeShifter;
8699 parentObj.channel4envelopeType = ((data & 0x08) == 0x08);
8700 parentObj.memory[0xFF21] = data;
8701 parentObj.channel4UpdateCache();
8702 parentObj.channel4VolumeEnableCheck();
8705 this.memoryHighWriter[0x22] = this.memoryWriter[0xFF22] = function (parentObj, address, data) {
8706 if (parentObj.soundMasterEnabled) {
8707 parentObj.audioJIT();
8708 parentObj.channel4FrequencyPeriod = Math.max((data & 0x7) << 4, 8) << (data >> 4);
8709 var bitWidth = (data & 0x8);
8710 if ((bitWidth == 0x8 && parentObj.channel4BitRange == 0x7FFF) || (bitWidth == 0 && parentObj.channel4BitRange == 0x7F)) {
8711 parentObj.channel4lastSampleLookup = 0;
8712 parentObj.channel4BitRange = (bitWidth == 0x8) ? 0x7F : 0x7FFF;
8713 parentObj.channel4VolumeShifter = (bitWidth == 0x8) ? 7 : 15;
8714 parentObj.channel4currentVolume = parentObj.channel4envelopeVolume << parentObj.channel4VolumeShifter;
8715 parentObj.noiseSampleTable = (bitWidth == 0x8) ? parentObj.LSFR7Table : parentObj.LSFR15Table;
8717 parentObj.memory[0xFF22] = data;
8718 parentObj.channel4UpdateCache();
8721 this.memoryHighWriter[0x23] = this.memoryWriter[0xFF23] = function (parentObj, address, data) {
8722 if (parentObj.soundMasterEnabled) {
8723 parentObj.audioJIT();
8724 parentObj.memory[0xFF23] = data;
8725 parentObj.channel4consecutive = ((data & 0x40) == 0x0);
8727 var nr42 = parentObj.memory[0xFF21];
8728 parentObj.channel4envelopeVolume = nr42 >> 4;
8729 parentObj.channel4currentVolume = parentObj.channel4envelopeVolume << parentObj.channel4VolumeShifter;
8730 parentObj.channel4envelopeSweepsLast = (nr42 & 0x7) - 1;
8731 if (parentObj.channel4totalLength == 0) {
8732 parentObj.channel4totalLength = 0x40;
8734 if ((data & 0x40) == 0x40) {
8735 parentObj.memory[0xFF26] |= 0x8;
8738 parentObj.channel4EnableCheck();
8741 this.memoryHighWriter[0x24] = this.memoryWriter[0xFF24] = function (parentObj, address, data) {
8742 if (parentObj.soundMasterEnabled && parentObj.memory[0xFF24] != data) {
8743 parentObj.audioJIT();
8744 parentObj.memory[0xFF24] = data;
8745 parentObj.VinLeftChannelMasterVolume = ((data >> 4) & 0x07) + 1;
8746 parentObj.VinRightChannelMasterVolume = (data & 0x07) + 1;
8747 parentObj.mixerOutputLevelCache();
8750 this.memoryHighWriter[0x25] = this.memoryWriter[0xFF25] = function (parentObj, address, data) {
8751 if (parentObj.soundMasterEnabled && parentObj.memory[0xFF25] != data) {
8752 parentObj.audioJIT();
8753 parentObj.memory[0xFF25] = data;
8754 parentObj.rightChannel1 = ((data & 0x01) == 0x01);
8755 parentObj.rightChannel2 = ((data & 0x02) == 0x02);
8756 parentObj.rightChannel3 = ((data & 0x04) == 0x04);
8757 parentObj.rightChannel4 = ((data & 0x08) == 0x08);
8758 parentObj.leftChannel1 = ((data & 0x10) == 0x10);
8759 parentObj.leftChannel2 = ((data & 0x20) == 0x20);
8760 parentObj.leftChannel3 = ((data & 0x40) == 0x40);
8761 parentObj.leftChannel4 = (data > 0x7F);
8762 parentObj.channel1OutputLevelCache();
8763 parentObj.channel2OutputLevelCache();
8764 parentObj.channel3OutputLevelCache();
8765 parentObj.channel4OutputLevelCache();
8768 this.memoryHighWriter[0x26] = this.memoryWriter[0xFF26] = function (parentObj, address, data) {
8769 parentObj.audioJIT();
8770 if (!parentObj.soundMasterEnabled && data > 0x7F) {
8771 parentObj.memory[0xFF26] = 0x80;
8772 parentObj.soundMasterEnabled = true;
8773 parentObj.initializeAudioStartState();
8775 else if (parentObj.soundMasterEnabled && data < 0x80) {
8776 parentObj.memory[0xFF26] = 0;
8777 parentObj.soundMasterEnabled = false;
8778 //GBDev wiki says the registers are written with zeros on power off:
8779 for (var index = 0xFF10; index < 0xFF26; index++) {
8780 parentObj.memoryWriter[index](parentObj, index, 0);
8784 //0xFF27 to 0xFF2F don't do anything...
8785 this.memoryHighWriter[0x27] = this.memoryWriter[0xFF27] = this.cartIgnoreWrite;
8786 this.memoryHighWriter[0x28] = this.memoryWriter[0xFF28] = this.cartIgnoreWrite;
8787 this.memoryHighWriter[0x29] = this.memoryWriter[0xFF29] = this.cartIgnoreWrite;
8788 this.memoryHighWriter[0x2A] = this.memoryWriter[0xFF2A] = this.cartIgnoreWrite;
8789 this.memoryHighWriter[0x2B] = this.memoryWriter[0xFF2B] = this.cartIgnoreWrite;
8790 this.memoryHighWriter[0x2C] = this.memoryWriter[0xFF2C] = this.cartIgnoreWrite;
8791 this.memoryHighWriter[0x2D] = this.memoryWriter[0xFF2D] = this.cartIgnoreWrite;
8792 this.memoryHighWriter[0x2E] = this.memoryWriter[0xFF2E] = this.cartIgnoreWrite;
8793 this.memoryHighWriter[0x2F] = this.memoryWriter[0xFF2F] = this.cartIgnoreWrite;
8795 this.memoryHighWriter[0x30] = this.memoryWriter[0xFF30] = function (parentObj, address, data) {
8796 parentObj.channel3WriteRAM(0, data);
8798 this.memoryHighWriter[0x31] = this.memoryWriter[0xFF31] = function (parentObj, address, data) {
8799 parentObj.channel3WriteRAM(0x1, data);
8801 this.memoryHighWriter[0x32] = this.memoryWriter[0xFF32] = function (parentObj, address, data) {
8802 parentObj.channel3WriteRAM(0x2, data);
8804 this.memoryHighWriter[0x33] = this.memoryWriter[0xFF33] = function (parentObj, address, data) {
8805 parentObj.channel3WriteRAM(0x3, data);
8807 this.memoryHighWriter[0x34] = this.memoryWriter[0xFF34] = function (parentObj, address, data) {
8808 parentObj.channel3WriteRAM(0x4, data);
8810 this.memoryHighWriter[0x35] = this.memoryWriter[0xFF35] = function (parentObj, address, data) {
8811 parentObj.channel3WriteRAM(0x5, data);
8813 this.memoryHighWriter[0x36] = this.memoryWriter[0xFF36] = function (parentObj, address, data) {
8814 parentObj.channel3WriteRAM(0x6, data);
8816 this.memoryHighWriter[0x37] = this.memoryWriter[0xFF37] = function (parentObj, address, data) {
8817 parentObj.channel3WriteRAM(0x7, data);
8819 this.memoryHighWriter[0x38] = this.memoryWriter[0xFF38] = function (parentObj, address, data) {
8820 parentObj.channel3WriteRAM(0x8, data);
8822 this.memoryHighWriter[0x39] = this.memoryWriter[0xFF39] = function (parentObj, address, data) {
8823 parentObj.channel3WriteRAM(0x9, data);
8825 this.memoryHighWriter[0x3A] = this.memoryWriter[0xFF3A] = function (parentObj, address, data) {
8826 parentObj.channel3WriteRAM(0xA, data);
8828 this.memoryHighWriter[0x3B] = this.memoryWriter[0xFF3B] = function (parentObj, address, data) {
8829 parentObj.channel3WriteRAM(0xB, data);
8831 this.memoryHighWriter[0x3C] = this.memoryWriter[0xFF3C] = function (parentObj, address, data) {
8832 parentObj.channel3WriteRAM(0xC, data);
8834 this.memoryHighWriter[0x3D] = this.memoryWriter[0xFF3D] = function (parentObj, address, data) {
8835 parentObj.channel3WriteRAM(0xD, data);
8837 this.memoryHighWriter[0x3E] = this.memoryWriter[0xFF3E] = function (parentObj, address, data) {
8838 parentObj.channel3WriteRAM(0xE, data);
8840 this.memoryHighWriter[0x3F] = this.memoryWriter[0xFF3F] = function (parentObj, address, data) {
8841 parentObj.channel3WriteRAM(0xF, data);
8844 this.memoryHighWriter[0x42] = this.memoryWriter[0xFF42] = function (parentObj, address, data) {
8845 if (parentObj.backgroundY != data) {
8846 parentObj.midScanLineJIT();
8847 parentObj.backgroundY = data;
8851 this.memoryHighWriter[0x43] = this.memoryWriter[0xFF43] = function (parentObj, address, data) {
8852 if (parentObj.backgroundX != data) {
8853 parentObj.midScanLineJIT();
8854 parentObj.backgroundX = data;
8858 this.memoryHighWriter[0x44] = this.memoryWriter[0xFF44] = function (parentObj, address, data) {
8860 if (parentObj.LCDisOn) {
8861 //Gambatte says to do this:
8862 parentObj.modeSTAT = 2;
8863 parentObj.midScanlineOffset = -1;
8864 parentObj.totalLinesPassed = parentObj.currentX = parentObj.queuedScanLines = parentObj.lastUnrenderedLine = parentObj.LCDTicks = parentObj.STATTracker = parentObj.actualScanLine = parentObj.memory[0xFF44] = 0;
8868 this.memoryHighWriter[0x45] = this.memoryWriter[0xFF45] = function (parentObj, address, data) {
8869 if (parentObj.memory[0xFF45] != data) {
8870 parentObj.memory[0xFF45] = data;
8871 if (parentObj.LCDisOn) {
8872 parentObj.matchLYC(); //Get the compare of the first scan line.
8877 this.memoryHighWriter[0x4A] = this.memoryWriter[0xFF4A] = function (parentObj, address, data) {
8878 if (parentObj.windowY != data) {
8879 parentObj.midScanLineJIT();
8880 parentObj.windowY = data;
8884 this.memoryHighWriter[0x4B] = this.memoryWriter[0xFF4B] = function (parentObj, address, data) {
8885 if (parentObj.memory[0xFF4B] != data) {
8886 parentObj.midScanLineJIT();
8887 parentObj.memory[0xFF4B] = data;
8888 parentObj.windowX = data - 7;
8891 this.memoryHighWriter[0x72] = this.memoryWriter[0xFF72] = function (parentObj, address, data) {
8892 parentObj.memory[0xFF72] = data;
8894 this.memoryHighWriter[0x73] = this.memoryWriter[0xFF73] = function (parentObj, address, data) {
8895 parentObj.memory[0xFF73] = data;
8897 this.memoryHighWriter[0x75] = this.memoryWriter[0xFF75] = function (parentObj, address, data) {
8898 parentObj.memory[0xFF75] = data;
8900 this.memoryHighWriter[0x76] = this.memoryWriter[0xFF76] = this.cartIgnoreWrite;
8901 this.memoryHighWriter[0x77] = this.memoryWriter[0xFF77] = this.cartIgnoreWrite;
8902 //IE (Interrupt Enable)
8903 this.memoryHighWriter[0xFF] = this.memoryWriter[0xFFFF] = function (parentObj, address, data) {
8904 parentObj.interruptsEnabled = data;
8905 parentObj.checkIRQMatching();
8907 this.recompileModelSpecificIOWriteHandling();
8908 this.recompileBootIOWriteHandling();
8910 GameBoyCore.prototype.recompileModelSpecificIOWriteHandling = function () {
8912 //GameBoy Color Specific I/O:
8913 //SC (Serial Transfer Control Register)
8914 this.memoryHighWriter[0x2] = this.memoryWriter[0xFF02] = function (parentObj, address, data) {
8915 if (((data & 0x1) == 0x1)) {
8917 parentObj.memory[0xFF02] = (data & 0x7F);
8918 parentObj.serialTimer = ((data & 0x2) == 0) ? 4096 : 128; //Set the Serial IRQ counter.
8919 parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = ((data & 0x2) == 0) ? 512 : 16; //Set the transfer data shift counter.
8923 parentObj.memory[0xFF02] = data;
8924 parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = parentObj.serialTimer = 0; //Zero the timers, since we're emulating as if nothing is connected.
8927 this.memoryHighWriter[0x40] = this.memoryWriter[0xFF40] = function (parentObj, address, data) {
8928 if (parentObj.memory[0xFF40] != data) {
8929 parentObj.midScanLineJIT();
8930 var temp_var = (data > 0x7F);
8931 if (temp_var != parentObj.LCDisOn) {
8932 //When the display mode changes...
8933 parentObj.LCDisOn = temp_var;
8934 parentObj.memory[0xFF41] &= 0x78;
8935 parentObj.midScanlineOffset = -1;
8936 parentObj.totalLinesPassed = parentObj.currentX = parentObj.queuedScanLines = parentObj.lastUnrenderedLine = parentObj.STATTracker = parentObj.LCDTicks = parentObj.actualScanLine = parentObj.memory[0xFF44] = 0;
8937 if (parentObj.LCDisOn) {
8938 parentObj.modeSTAT = 2;
8939 parentObj.matchLYC(); //Get the compare of the first scan line.
8940 parentObj.LCDCONTROL = parentObj.LINECONTROL;
8943 parentObj.modeSTAT = 0;
8944 parentObj.LCDCONTROL = parentObj.DISPLAYOFFCONTROL;
8945 parentObj.DisplayShowOff();
8947 parentObj.interruptsRequested &= 0xFD;
8949 parentObj.gfxWindowCHRBankPosition = ((data & 0x40) == 0x40) ? 0x400 : 0;
8950 parentObj.gfxWindowDisplay = ((data & 0x20) == 0x20);
8951 parentObj.gfxBackgroundBankOffset = ((data & 0x10) == 0x10) ? 0 : 0x80;
8952 parentObj.gfxBackgroundCHRBankPosition = ((data & 0x08) == 0x08) ? 0x400 : 0;
8953 parentObj.gfxSpriteNormalHeight = ((data & 0x04) == 0);
8954 parentObj.gfxSpriteShow = ((data & 0x02) == 0x02);
8955 parentObj.BGPriorityEnabled = ((data & 0x01) == 0x01);
8956 parentObj.priorityFlaggingPathRebuild(); //Special case the priority flagging as an optimization.
8957 parentObj.memory[0xFF40] = data;
8960 this.memoryHighWriter[0x41] = this.memoryWriter[0xFF41] = function (parentObj, address, data) {
8961 parentObj.LYCMatchTriggerSTAT = ((data & 0x40) == 0x40);
8962 parentObj.mode2TriggerSTAT = ((data & 0x20) == 0x20);
8963 parentObj.mode1TriggerSTAT = ((data & 0x10) == 0x10);
8964 parentObj.mode0TriggerSTAT = ((data & 0x08) == 0x08);
8965 parentObj.memory[0xFF41] = data & 0x78;
8967 this.memoryHighWriter[0x46] = this.memoryWriter[0xFF46] = function (parentObj, address, data) {
8968 parentObj.memory[0xFF46] = data;
8972 var stat = parentObj.modeSTAT;
8973 parentObj.modeSTAT = 0;
8976 newData = parentObj.memoryReader[data](parentObj, data++);
8977 if (newData != parentObj.memory[address]) {
8978 //JIT the graphics render queue:
8979 parentObj.modeSTAT = stat;
8980 parentObj.graphicsJIT();
8981 parentObj.modeSTAT = 0;
8982 parentObj.memory[address++] = newData;
8985 } while (++address < 0xFEA0);
8986 if (address < 0xFEA0) {
8988 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
8989 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
8990 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
8991 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
8992 } while (address < 0xFEA0);
8994 parentObj.modeSTAT = stat;
8998 this.memoryHighWriter[0x4D] = this.memoryWriter[0xFF4D] = function (parentObj, address, data) {
8999 parentObj.memory[0xFF4D] = (data & 0x7F) | (parentObj.memory[0xFF4D] & 0x80);
9001 this.memoryHighWriter[0x4F] = this.memoryWriter[0xFF4F] = function (parentObj, address, data) {
9002 parentObj.currVRAMBank = data & 0x01;
9003 if (parentObj.currVRAMBank > 0) {
9004 parentObj.BGCHRCurrentBank = parentObj.BGCHRBank2;
9007 parentObj.BGCHRCurrentBank = parentObj.BGCHRBank1;
9009 //Only writable by GBC.
9011 this.memoryHighWriter[0x51] = this.memoryWriter[0xFF51] = function (parentObj, address, data) {
9012 if (!parentObj.hdmaRunning) {
9013 parentObj.memory[0xFF51] = data;
9016 this.memoryHighWriter[0x52] = this.memoryWriter[0xFF52] = function (parentObj, address, data) {
9017 if (!parentObj.hdmaRunning) {
9018 parentObj.memory[0xFF52] = data & 0xF0;
9021 this.memoryHighWriter[0x53] = this.memoryWriter[0xFF53] = function (parentObj, address, data) {
9022 if (!parentObj.hdmaRunning) {
9023 parentObj.memory[0xFF53] = data & 0x1F;
9026 this.memoryHighWriter[0x54] = this.memoryWriter[0xFF54] = function (parentObj, address, data) {
9027 if (!parentObj.hdmaRunning) {
9028 parentObj.memory[0xFF54] = data & 0xF0;
9031 this.memoryHighWriter[0x55] = this.memoryWriter[0xFF55] = function (parentObj, address, data) {
9032 if (!parentObj.hdmaRunning) {
9033 if ((data & 0x80) == 0) {
9035 parentObj.DMAWrite((data & 0x7F) + 1);
9036 parentObj.memory[0xFF55] = 0xFF; //Transfer completed.
9040 parentObj.hdmaRunning = true;
9041 parentObj.memory[0xFF55] = data & 0x7F;
9044 else if ((data & 0x80) == 0) {
9046 parentObj.hdmaRunning = false;
9047 parentObj.memory[0xFF55] |= 0x80;
9050 parentObj.memory[0xFF55] = data & 0x7F;
9053 this.memoryHighWriter[0x68] = this.memoryWriter[0xFF68] = function (parentObj, address, data) {
9054 parentObj.memory[0xFF69] = parentObj.gbcBGRawPalette[data & 0x3F];
9055 parentObj.memory[0xFF68] = data;
9057 this.memoryHighWriter[0x69] = this.memoryWriter[0xFF69] = function (parentObj, address, data) {
9058 parentObj.updateGBCBGPalette(parentObj.memory[0xFF68] & 0x3F, data);
9059 if (parentObj.memory[0xFF68] > 0x7F) { // high bit = autoincrement
9060 var next = ((parentObj.memory[0xFF68] + 1) & 0x3F);
9061 parentObj.memory[0xFF68] = (next | 0x80);
9062 parentObj.memory[0xFF69] = parentObj.gbcBGRawPalette[next];
9065 parentObj.memory[0xFF69] = data;
9068 this.memoryHighWriter[0x6A] = this.memoryWriter[0xFF6A] = function (parentObj, address, data) {
9069 parentObj.memory[0xFF6B] = parentObj.gbcOBJRawPalette[data & 0x3F];
9070 parentObj.memory[0xFF6A] = data;
9072 this.memoryHighWriter[0x6B] = this.memoryWriter[0xFF6B] = function (parentObj, address, data) {
9073 parentObj.updateGBCOBJPalette(parentObj.memory[0xFF6A] & 0x3F, data);
9074 if (parentObj.memory[0xFF6A] > 0x7F) { // high bit = autoincrement
9075 var next = ((parentObj.memory[0xFF6A] + 1) & 0x3F);
9076 parentObj.memory[0xFF6A] = (next | 0x80);
9077 parentObj.memory[0xFF6B] = parentObj.gbcOBJRawPalette[next];
9080 parentObj.memory[0xFF6B] = data;
9084 this.memoryHighWriter[0x70] = this.memoryWriter[0xFF70] = function (parentObj, address, data) {
9085 var addressCheck = (parentObj.memory[0xFF51] << 8) | parentObj.memory[0xFF52]; //Cannot change the RAM bank while WRAM is the source of a running HDMA.
9086 if (!parentObj.hdmaRunning || addressCheck < 0xD000 || addressCheck >= 0xE000) {
9087 parentObj.gbcRamBank = Math.max(data & 0x07, 1); //Bank range is from 1-7
9088 parentObj.gbcRamBankPosition = ((parentObj.gbcRamBank - 1) << 12) - 0xD000;
9089 parentObj.gbcRamBankPositionECHO = parentObj.gbcRamBankPosition - 0x2000;
9091 parentObj.memory[0xFF70] = data; //Bit 6 cannot be written to.
9093 this.memoryHighWriter[0x74] = this.memoryWriter[0xFF74] = function (parentObj, address, data) {
9094 parentObj.memory[0xFF74] = data;
9098 //Fill in the GameBoy Color I/O registers as normal RAM for GameBoy compatibility:
9099 //SC (Serial Transfer Control Register)
9100 this.memoryHighWriter[0x2] = this.memoryWriter[0xFF02] = function (parentObj, address, data) {
9101 if (((data & 0x1) == 0x1)) {
9103 parentObj.memory[0xFF02] = (data & 0x7F);
9104 parentObj.serialTimer = 4096; //Set the Serial IRQ counter.
9105 parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = 512; //Set the transfer data shift counter.
9109 parentObj.memory[0xFF02] = data;
9110 parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = parentObj.serialTimer = 0; //Zero the timers, since we're emulating as if nothing is connected.
9113 this.memoryHighWriter[0x40] = this.memoryWriter[0xFF40] = function (parentObj, address, data) {
9114 if (parentObj.memory[0xFF40] != data) {
9115 parentObj.midScanLineJIT();
9116 var temp_var = (data > 0x7F);
9117 if (temp_var != parentObj.LCDisOn) {
9118 //When the display mode changes...
9119 parentObj.LCDisOn = temp_var;
9120 parentObj.memory[0xFF41] &= 0x78;
9121 parentObj.midScanlineOffset = -1;
9122 parentObj.totalLinesPassed = parentObj.currentX = parentObj.queuedScanLines = parentObj.lastUnrenderedLine = parentObj.STATTracker = parentObj.LCDTicks = parentObj.actualScanLine = parentObj.memory[0xFF44] = 0;
9123 if (parentObj.LCDisOn) {
9124 parentObj.modeSTAT = 2;
9125 parentObj.matchLYC(); //Get the compare of the first scan line.
9126 parentObj.LCDCONTROL = parentObj.LINECONTROL;
9129 parentObj.modeSTAT = 0;
9130 parentObj.LCDCONTROL = parentObj.DISPLAYOFFCONTROL;
9131 parentObj.DisplayShowOff();
9133 parentObj.interruptsRequested &= 0xFD;
9135 parentObj.gfxWindowCHRBankPosition = ((data & 0x40) == 0x40) ? 0x400 : 0;
9136 parentObj.gfxWindowDisplay = (data & 0x20) == 0x20;
9137 parentObj.gfxBackgroundBankOffset = ((data & 0x10) == 0x10) ? 0 : 0x80;
9138 parentObj.gfxBackgroundCHRBankPosition = ((data & 0x08) == 0x08) ? 0x400 : 0;
9139 parentObj.gfxSpriteNormalHeight = ((data & 0x04) == 0);
9140 parentObj.gfxSpriteShow = (data & 0x02) == 0x02;
9141 parentObj.bgEnabled = ((data & 0x01) == 0x01);
9142 parentObj.memory[0xFF40] = data;
9145 this.memoryHighWriter[0x41] = this.memoryWriter[0xFF41] = function (parentObj, address, data) {
9146 parentObj.LYCMatchTriggerSTAT = ((data & 0x40) == 0x40);
9147 parentObj.mode2TriggerSTAT = ((data & 0x20) == 0x20);
9148 parentObj.mode1TriggerSTAT = ((data & 0x10) == 0x10);
9149 parentObj.mode0TriggerSTAT = ((data & 0x08) == 0x08);
9150 parentObj.memory[0xFF41] = data & 0x78;
9151 if ((!parentObj.usedBootROM || !parentObj.usedGBCBootROM) && parentObj.LCDisOn && parentObj.modeSTAT < 2) {
9152 parentObj.interruptsRequested |= 0x2;
9153 parentObj.checkIRQMatching();
9156 this.memoryHighWriter[0x46] = this.memoryWriter[0xFF46] = function (parentObj, address, data) {
9157 parentObj.memory[0xFF46] = data;
9158 if (data > 0x7F && data < 0xE0) { //DMG cannot DMA from the ROM banks.
9161 var stat = parentObj.modeSTAT;
9162 parentObj.modeSTAT = 0;
9165 newData = parentObj.memoryReader[data](parentObj, data++);
9166 if (newData != parentObj.memory[address]) {
9167 //JIT the graphics render queue:
9168 parentObj.modeSTAT = stat;
9169 parentObj.graphicsJIT();
9170 parentObj.modeSTAT = 0;
9171 parentObj.memory[address++] = newData;
9174 } while (++address < 0xFEA0);
9175 if (address < 0xFEA0) {
9177 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
9178 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
9179 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
9180 parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
9181 } while (address < 0xFEA0);
9183 parentObj.modeSTAT = stat;
9186 this.memoryHighWriter[0x47] = this.memoryWriter[0xFF47] = function (parentObj, address, data) {
9187 if (parentObj.memory[0xFF47] != data) {
9188 parentObj.midScanLineJIT();
9189 parentObj.updateGBBGPalette(data);
9190 parentObj.memory[0xFF47] = data;
9193 this.memoryHighWriter[0x48] = this.memoryWriter[0xFF48] = function (parentObj, address, data) {
9194 if (parentObj.memory[0xFF48] != data) {
9195 parentObj.midScanLineJIT();
9196 parentObj.updateGBOBJPalette(0, data);
9197 parentObj.memory[0xFF48] = data;
9200 this.memoryHighWriter[0x49] = this.memoryWriter[0xFF49] = function (parentObj, address, data) {
9201 if (parentObj.memory[0xFF49] != data) {
9202 parentObj.midScanLineJIT();
9203 parentObj.updateGBOBJPalette(4, data);
9204 parentObj.memory[0xFF49] = data;
9207 this.memoryHighWriter[0x4D] = this.memoryWriter[0xFF4D] = function (parentObj, address, data) {
9208 parentObj.memory[0xFF4D] = data;
9210 this.memoryHighWriter[0x4F] = this.memoryWriter[0xFF4F] = this.cartIgnoreWrite; //Not writable in DMG mode.
9211 this.memoryHighWriter[0x55] = this.memoryWriter[0xFF55] = this.cartIgnoreWrite;
9212 this.memoryHighWriter[0x68] = this.memoryWriter[0xFF68] = this.cartIgnoreWrite;
9213 this.memoryHighWriter[0x69] = this.memoryWriter[0xFF69] = this.cartIgnoreWrite;
9214 this.memoryHighWriter[0x6A] = this.memoryWriter[0xFF6A] = this.cartIgnoreWrite;
9215 this.memoryHighWriter[0x6B] = this.memoryWriter[0xFF6B] = this.cartIgnoreWrite;
9216 this.memoryHighWriter[0x6C] = this.memoryWriter[0xFF6C] = this.cartIgnoreWrite;
9217 this.memoryHighWriter[0x70] = this.memoryWriter[0xFF70] = this.cartIgnoreWrite;
9218 this.memoryHighWriter[0x74] = this.memoryWriter[0xFF74] = this.cartIgnoreWrite;
9221 GameBoyCore.prototype.recompileBootIOWriteHandling = function () {
9222 //Boot I/O Registers:
9223 if (this.inBootstrap) {
9224 this.memoryHighWriter[0x50] = this.memoryWriter[0xFF50] = function (parentObj, address, data) {
9225 cout("Boot ROM reads blocked: Bootstrap process has ended.", 0);
9226 parentObj.inBootstrap = false;
9227 parentObj.disableBootROM(); //Fill in the boot ROM ranges with ROM bank 0 ROM ranges
9228 parentObj.memory[0xFF50] = data; //Bits are sustained in memory?
9231 this.memoryHighWriter[0x6C] = this.memoryWriter[0xFF6C] = function (parentObj, address, data) {
9232 if (parentObj.inBootstrap) {
9233 parentObj.cGBC = ((data & 0x1) == 0);
9234 //Exception to the GBC identifying code:
9235 if (parentObj.name + parentObj.gameCode + parentObj.ROM[0x143] == "Game and Watch 50") {
9236 parentObj.cGBC = true;
9237 cout("Created a boot exception for Game and Watch Gallery 2 (GBC ID byte is wrong on the cartridge).", 1);
9239 cout("Booted to GBC Mode: " + parentObj.cGBC, 0);
9241 parentObj.memory[0xFF6C] = data;
9246 //Lockout the ROMs from accessing the BOOT ROM control register:
9247 this.memoryHighWriter[0x50] = this.memoryWriter[0xFF50] = this.cartIgnoreWrite;
9251 GameBoyCore.prototype.toTypedArray = function (baseArray, memtype) {
9253 // The following line was modified for benchmarking:
9254 if (settings[5] || (memtype != "float32" && GameBoyWindow.opera && this.checkForOperaMathBug())) {
9257 if (!baseArray || !baseArray.length) {
9260 var length = baseArray.length;
9263 var typedArrayTemp = new Uint8Array(length);
9266 var typedArrayTemp = new Int8Array(length);
9269 var typedArrayTemp = new Int32Array(length);
9272 var typedArrayTemp = new Float32Array(length);
9274 for (var index = 0; index < length; index++) {
9275 typedArrayTemp[index] = baseArray[index];
9277 return typedArrayTemp;
9280 cout("Could not convert an array to a typed array: " + error.message, 1);
9284 GameBoyCore.prototype.fromTypedArray = function (baseArray) {
9286 if (!baseArray || !baseArray.length) {
9290 for (var index = 0; index < baseArray.length; ++index) {
9291 arrayTemp[index] = baseArray[index];
9296 cout("Conversion from a typed array failed: " + error.message, 1);
9300 GameBoyCore.prototype.getTypedArray = function (length, defaultValue, numberType) {
9303 throw(new Error(""));
9305 // The following line was modified for benchmarking:
9306 if (numberType != "float32" && GameBoyWindow.opera && this.checkForOperaMathBug()) {
9307 //Caught Opera breaking typed array math:
9308 throw(new Error(""));
9310 switch (numberType) {
9312 var arrayHandle = new Int8Array(length);
9315 var arrayHandle = new Uint8Array(length);
9318 var arrayHandle = new Int32Array(length);
9321 var arrayHandle = new Float32Array(length);
9323 if (defaultValue != 0) {
9325 while (index < length) {
9326 arrayHandle[index++] = defaultValue;
9331 cout("Could not convert an array to a typed array: " + error.message, 1);
9332 var arrayHandle = [];
9334 while (index < length) {
9335 arrayHandle[index++] = defaultValue;
9340 GameBoyCore.prototype.checkForOperaMathBug = function () {
9341 var testTypedArray = new Uint8Array(1);
9342 testTypedArray[0] = -1;
9343 testTypedArray[0] >>= 0;
9344 if (testTypedArray[0] != 0xFF) {
9345 cout("Detected faulty math by your browser.", 2);
9353 // End of js/GameBoyCore.js file.
9355 // Start of js/GameBoyIO.js file.
9358 var gameboy = null; //GameBoyCore object.
9359 var gbRunInterval = null; //GameBoyCore Timer
9360 var settings = [ //Some settings.
9361 true, //Turn on sound.
9362 false, //Boot with boot ROM first? (set to false for benchmarking)
9363 false, //Give priority to GameBoy mode
9364 [39, 37, 38, 40, 88, 90, 16, 13], //Keyboard button map.
9365 true, //Colorize GB mode?
9366 false, //Disallow typed arrays?
9367 4, //Interval for the emulator loop.
9368 15, //Audio buffer minimum span amount over x interpreter iterations.
9369 30, //Audio buffer maximum span amount over x interpreter iterations.
9370 false, //Override to allow for MBC1 instead of ROM only (compatibility for broken 3rd-party cartridges).
9371 false, //Override MBC RAM disabling and always allow reading and writing to the banks.
9372 false, //Use the GameBoy boot ROM instead of the GameBoy Color boot ROM.
9373 false, //Scale the canvas in JS, or let the browser scale the canvas?
9374 0x10, //Internal audio buffer pre-interpolation factor.
9375 1 //Volume level set.
9377 function start(canvas, ROM) {
9378 clearLastEmulation();
9379 autoSave(); //If we are about to load a new game, then save the last one...
9380 gameboy = new GameBoyCore(canvas, ROM);
9381 gameboy.openMBC = openSRAM;
9382 gameboy.openRTC = openRTC;
9387 if (GameBoyEmulatorInitialized()) {
9388 if (!GameBoyEmulatorPlaying()) {
9389 gameboy.stopEmulator &= 1;
9390 cout("Starting the iterator.", 0);
9391 var dateObj = new_Date(); // The line is changed for benchmarking.
9392 gameboy.firstIteration = dateObj.getTime();
9393 gameboy.iterations = 0;
9394 // The following lines are commented out for benchmarking.
9395 // gbRunInterval = setInterval(function () {
9396 // if (!document.hidden && !document.msHidden && !document.mozHidden && !document.webkitHidden) {
9402 cout("The GameBoy core is already running.", 1);
9406 cout("GameBoy core cannot run while it has not been initialized.", 1);
9410 if (GameBoyEmulatorInitialized()) {
9411 if (GameBoyEmulatorPlaying()) {
9412 clearLastEmulation();
9415 cout("GameBoy core has already been paused.", 1);
9419 cout("GameBoy core cannot be paused while it has not been initialized.", 1);
9422 function clearLastEmulation() {
9423 if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
9424 clearInterval(gbRunInterval);
9425 gameboy.stopEmulator |= 2;
9426 cout("The previous emulation has been cleared.", 0);
9429 cout("No previous emulation was found to be cleared.", 0);
9433 if (GameBoyEmulatorInitialized()) {
9435 var state_suffix = 0;
9436 while (findValue("FREEZE_" + gameboy.name + "_" + state_suffix) != null) {
9439 setValue("FREEZE_" + gameboy.name + "_" + state_suffix, gameboy.saveState());
9440 cout("Saved the current state as: FREEZE_" + gameboy.name + "_" + state_suffix, 0);
9443 cout("Could not save the current emulation state(\"" + error.message + "\").", 2);
9447 cout("GameBoy core cannot be saved while it has not been initialized.", 1);
9450 function saveSRAM() {
9451 if (GameBoyEmulatorInitialized()) {
9452 if (gameboy.cBATT) {
9454 var sram = gameboy.saveSRAMState();
9455 if (sram.length > 0) {
9456 cout("Saving the SRAM...", 0);
9457 if (findValue("SRAM_" + gameboy.name) != null) {
9458 //Remove the outdated storage format save:
9459 cout("Deleting the old SRAM save due to outdated format.", 0);
9460 deleteValue("SRAM_" + gameboy.name);
9462 setValue("B64_SRAM_" + gameboy.name, arrayToBase64(sram));
9465 cout("SRAM could not be saved because it was empty.", 1);
9469 cout("Could not save the current emulation state(\"" + error.message + "\").", 2);
9473 cout("Cannot save a game that does not have battery backed SRAM specified.", 1);
9478 cout("GameBoy core cannot be saved while it has not been initialized.", 1);
9481 function saveRTC() { //Execute this when SRAM is being saved as well.
9482 if (GameBoyEmulatorInitialized()) {
9483 if (gameboy.cTIMER) {
9485 cout("Saving the RTC...", 0);
9486 setValue("RTC_" + gameboy.name, gameboy.saveRTCState());
9489 cout("Could not save the RTC of the current emulation state(\"" + error.message + "\").", 2);
9494 cout("GameBoy core cannot be saved while it has not been initialized.", 1);
9497 function autoSave() {
9498 if (GameBoyEmulatorInitialized()) {
9499 cout("Automatically saving the SRAM.", 0);
9504 function openSRAM(filename) {
9506 if (findValue("B64_SRAM_" + filename) != null) {
9507 cout("Found a previous SRAM state (Will attempt to load).", 0);
9508 return base64ToArray(findValue("B64_SRAM_" + filename));
9510 else if (findValue("SRAM_" + filename) != null) {
9511 cout("Found a previous SRAM state (Will attempt to load).", 0);
9512 return findValue("SRAM_" + filename);
9515 cout("Could not find any previous SRAM copy for the current ROM.", 0);
9519 cout("Could not open the SRAM of the saved emulation state.", 2);
9523 function openRTC(filename) {
9525 if (findValue("RTC_" + filename) != null) {
9526 cout("Found a previous RTC state (Will attempt to load).", 0);
9527 return findValue("RTC_" + filename);
9530 cout("Could not find any previous RTC copy for the current ROM.", 0);
9534 cout("Could not open the RTC data of the saved emulation state.", 2);
9538 function openState(filename, canvas) {
9540 if (findValue(filename) != null) {
9542 clearLastEmulation();
9543 cout("Attempting to run a saved emulation state.", 0);
9544 gameboy = new GameBoyCore(canvas, "");
9545 gameboy.savedStateFileName = filename;
9546 gameboy.returnFromState(findValue(filename));
9550 alert(error.message + " file: " + error.fileName + " line: " + error.lineNumber);
9554 cout("Could not find the save state " + filename + "\".", 2);
9558 cout("Could not open the saved emulation state.", 2);
9561 function import_save(blobData) {
9562 blobData = decodeBlob(blobData);
9563 if (blobData && blobData.blobs) {
9564 if (blobData.blobs.length > 0) {
9565 for (var index = 0; index < blobData.blobs.length; ++index) {
9566 cout("Importing blob \"" + blobData.blobs[index].blobID + "\"", 0);
9567 if (blobData.blobs[index].blobContent) {
9568 if (blobData.blobs[index].blobID.substring(0, 5) == "SRAM_") {
9569 setValue("B64_" + blobData.blobs[index].blobID, base64(blobData.blobs[index].blobContent));
9572 setValue(blobData.blobs[index].blobID, JSON.parse(blobData.blobs[index].blobContent));
9575 else if (blobData.blobs[index].blobID) {
9576 cout("Save file imported had blob \"" + blobData.blobs[index].blobID + "\" with no blob data interpretable.", 2);
9579 cout("Blob chunk information missing completely.", 2);
9584 cout("Could not decode the imported file.", 2);
9588 cout("Could not decode the imported file.", 2);
9591 function generateBlob(keyName, encodedData) {
9592 //Append the file format prefix:
9593 var saveString = "EMULATOR_DATA";
9594 var consoleID = "GameBoy";
9595 //Figure out the length:
9596 var totalLength = (saveString.length + 4 + (1 + consoleID.length)) + ((1 + keyName.length) + (4 + encodedData.length));
9597 //Append the total length in bytes:
9598 saveString += to_little_endian_dword(totalLength);
9599 //Append the console ID text's length:
9600 saveString += to_byte(consoleID.length);
9601 //Append the console ID text:
9602 saveString += consoleID;
9603 //Append the blob ID:
9604 saveString += to_byte(keyName.length);
9605 saveString += keyName;
9606 //Now append the save data:
9607 saveString += to_little_endian_dword(encodedData.length);
9608 saveString += encodedData;
9611 function generateMultiBlob(blobPairs) {
9612 var consoleID = "GameBoy";
9613 //Figure out the initial length:
9614 var totalLength = 13 + 4 + 1 + consoleID.length;
9615 //Append the console ID text's length:
9616 var saveString = to_byte(consoleID.length);
9617 //Append the console ID text:
9618 saveString += consoleID;
9620 var encodedData = "";
9621 //Now append all the blobs:
9622 for (var index = 0; index < blobPairs.length; ++index) {
9623 keyName = blobPairs[index][0];
9624 encodedData = blobPairs[index][1];
9625 //Append the blob ID:
9626 saveString += to_byte(keyName.length);
9627 saveString += keyName;
9628 //Now append the save data:
9629 saveString += to_little_endian_dword(encodedData.length);
9630 saveString += encodedData;
9631 //Update the total length:
9632 totalLength += 1 + keyName.length + 4 + encodedData.length;
9634 //Now add the prefix:
9635 saveString = "EMULATOR_DATA" + to_little_endian_dword(totalLength) + saveString;
9638 function decodeBlob(blobData) {
9639 /*Format is as follows:
9640 - 13 byte string "EMULATOR_DATA"
9641 - 4 byte total size (including these 4 bytes).
9642 - 1 byte Console type ID length
9643 - Console type ID text of 8 bit size
9645 - 1 byte blob ID length
9646 - blob ID text (Used to say what the data is (SRAM/freeze state/etc...))
9647 - 4 byte blob length
9648 - blob length of 32 bit size
9651 var length = blobData.length;
9652 var blobProperties = {};
9653 blobProperties.consoleID = null;
9654 var blobsCount = -1;
9655 blobProperties.blobs = [];
9657 if (blobData.substring(0, 13) == "EMULATOR_DATA") {
9658 var length = Math.min(((blobData.charCodeAt(16) & 0xFF) << 24) | ((blobData.charCodeAt(15) & 0xFF) << 16) | ((blobData.charCodeAt(14) & 0xFF) << 8) | (blobData.charCodeAt(13) & 0xFF), length);
9659 var consoleIDLength = blobData.charCodeAt(17) & 0xFF;
9660 if (length > 17 + consoleIDLength) {
9661 blobProperties.consoleID = blobData.substring(18, 18 + consoleIDLength);
9662 var blobIDLength = 0;
9664 for (var index = 18 + consoleIDLength; index < length;) {
9665 blobIDLength = blobData.charCodeAt(index++) & 0xFF;
9666 if (index + blobIDLength < length) {
9667 blobProperties.blobs[++blobsCount] = {};
9668 blobProperties.blobs[blobsCount].blobID = blobData.substring(index, index + blobIDLength);
9669 index += blobIDLength;
9670 if (index + 4 < length) {
9671 blobLength = ((blobData.charCodeAt(index + 3) & 0xFF) << 24) | ((blobData.charCodeAt(index + 2) & 0xFF) << 16) | ((blobData.charCodeAt(index + 1) & 0xFF) << 8) | (blobData.charCodeAt(index) & 0xFF);
9673 if (index + blobLength <= length) {
9674 blobProperties.blobs[blobsCount].blobContent = blobData.substring(index, index + blobLength);
9675 index += blobLength;
9678 cout("Blob length check failed, blob determined to be incomplete.", 2);
9683 cout("Blob was incomplete, bailing out.", 2);
9688 cout("Blob was incomplete, bailing out.", 2);
9695 return blobProperties;
9697 function matchKey(key) { //Maps a keyboard key to a gameboy key.
9698 //Order: Right, Left, Up, Down, A, B, Select, Start
9699 for (var index = 0; index < settings[3].length; index++) {
9700 if (settings[3][index] == key) {
9706 function GameBoyEmulatorInitialized() {
9707 return (typeof gameboy == "object" && gameboy != null);
9709 function GameBoyEmulatorPlaying() {
9710 return ((gameboy.stopEmulator & 2) == 0);
9712 function GameBoyKeyDown(e) {
9713 if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
9714 var keycode = matchKey(e.keyCode);
9715 if (keycode >= 0 && keycode < 8) {
9716 gameboy.JoyPadEvent(keycode, true);
9724 function GameBoyKeyUp(e) {
9725 if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
9726 var keycode = matchKey(e.keyCode);
9727 if (keycode >= 0 && keycode < 8) {
9728 gameboy.JoyPadEvent(keycode, false);
9736 function GameBoyGyroSignalHandler(e) {
9737 if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
9738 if (e.gamma || e.beta) {
9739 gameboy.GyroEvent(e.gamma * Math.PI / 180, e.beta * Math.PI / 180);
9742 gameboy.GyroEvent(e.x, e.y);
9750 //The emulator will call this to sort out the canvas properties for (re)initialization.
9751 function initNewCanvas() {
9752 if (GameBoyEmulatorInitialized()) {
9753 gameboy.canvas.width = gameboy.canvas.clientWidth;
9754 gameboy.canvas.height = gameboy.canvas.clientHeight;
9757 //Call this when resizing the canvas:
9758 function initNewCanvasSize() {
9759 if (GameBoyEmulatorInitialized()) {
9760 if (!settings[12]) {
9761 if (gameboy.onscreenWidth != 160 || gameboy.onscreenHeight != 144) {
9766 if (gameboy.onscreenWidth != gameboy.canvas.clientWidth || gameboy.onscreenHeight != gameboy.canvas.clientHeight) {
9773 // End of js/GameBoyIO.js file.
9775 // Start of realtime.js file.
9776 // ROM code from Public Domain LPC2000 Demo "realtime" by AGO.
9778 var gameboy_rom='r+BPyZiEZwA+AeBPySAobeEq6gAgKlYj5WJv6SRmZjjhKuXqACDJ/////////////////////////////////xgHZwCYhGcA2fX6/3/1xdXlIRPKNgHN9f/h0cHx6gAg+hLKtyAC8cnwgLcoF/CC7hjgUT6Q4FOv4FLgVOCAPv/gVfHZ8IG3IALx2fBA7gjgQA8PD+YB7gHgT/CC4FHuEOCCPojgU6/gUuBU4IE+/uBV4ID6NMs86jTL8dkKCgoKbWFkZSBieSBhZ28uIGVtYWlsOmdvYnV6b3ZAeWFob28uY29tCnVybDogc3BlY2N5LmRhLnJ1CgoKCv///////wDDSgnO7WZmzA0ACwNzAIMADAANAAgRH4iJAA7czG7m3d3Zmbu7Z2NuDuzM3dyZn7u5Mz5BR08nUyBSRUFMVElNRSCAAAAAAgEDADMBSTQeIUD/y37I8P/1y4fg//BE/pEg+su+8eD/yT7A4EY+KD0g/cnF1eWvEQPK1RITEhMGAyEAyuXFTgYAIWAMCQkqEhMqEhPB4SMFIOrhrwYIzYsU4dHByf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAgMFBggJCwwOEBETFBYXGBobHR4fISIjJSYnKSorLC0uLzAxMjM0NTY3ODg5Ojo7PDw9PT4+Pj8/Pz9AQEBAQEBAQEBAPz8/Pz4+PT08PDs7Ojk5ODc2NTU0MzIxMC8uLCsqKSgmJSQjISAfHRwaGRcWFRMSEA8NCwoIBwUEAgH//fz6+ff29PPx8O7t6+ro5+Xk4uHg3t3c2tnY19bU09LR0M/OzczLysnJyMfGxsXFxMPDw8LCwcHBwcDAwMDAwMDAwMDBwcHBwsLDw8PExcXGxsfIycnKy8zNzs/Q0dLT1NXX2Nna3N3e4OHi5OXn6Onr7O7v8fL09vf5+vz9AAEECRAZJDFAUWR5kKnE4QAhRGmQueQRQHGk2RBJhMEAQYTJEFmk8UCR5DmQ6UShAGHEKZD5ZNFAsSSZEIkEgQCBBIkQmSSxQNFk+ZApxGEAoUTpkDnkkUDxpFkQyYRBAMGESRDZpHFAEeS5kGlEIQDhxKmQeWRRQDEkGRAJBAEAAQQJEBkkMUBRZHmQqcThACFEaZC55BFAcaTZEEmEwQBBhMkQWaTxQJHkOZDpRKEAYcQpkPlk0UCxJJkQiQSBAIEEiRCZJLFA0WT5kCnEYQChROmQOeSRQPGkWRDJhEEAwYRJENmkcUAR5LmQaUQhAOHEqZB5ZFFAMSQZEAkEAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAgICAgIDAwMDBAQEBAUFBQUGBgYHBwcICAkJCQoKCgsLDAwNDQ4ODw8QEBEREhITExQUFRUWFxcYGRkaGhscHB0eHh8gISEiIyQkJSYnJygpKisrLC0uLzAxMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1FSU1RVVldZWltcXV9gYWJkZWZnaWprbG5vcHJzdHZ3eXp7fX5/gYKEhYeIiouNjpCRk5SWl5manJ2foKKkpaepqqytr7GytLa3ubu9vsDCxMXHycvMztDS1NXX2dvd3+Hi5Obo6uzu8PL09vj6/P4A//z38Ofcz8CvnIdwVzwfAN+8l3BHHO/Aj1wn8Ld8PwC/fDfwp1wPwG8cx3AXvF8AnzzXcAecL8BP3Gfwd/x/AH/8d/Bn3E/AL5wHcNc8nwBfvBdwxxxvwA9cp/A3fL8AP3y38Cdcj8DvHEdwl7zfAB88V3CHnK/Az9zn8Pf8/wD//Pfw59zPwK+ch3BXPB8A37yXcEcc78CPXCfwt3w/AL98N/CnXA/AbxzHcBe8XwCfPNdwB5wvwE/cZ/B3/H8Af/x38GfcT8AvnAdw1zyfAF+8F3DHHG/AD1yn8Dd8vwA/fLfwJ1yPwO8cR3CXvN8AHzxXcIecr8DP3Ofw9/z/AP/////////////////////+/v7+/v79/f39/fz8/Pz8+/v7+vr6+vn5+fj4+Pf39/b29fX19PTz8/Ly8fHw8PDv7u7t7ezs6+vq6uno6Ofn5uXl5OPj4uHh4N/e3t3c3Nva2djY19bV1NTT0tHQz8/OzczLysnIx8bFxMPCwcDAvr28u7q5uLe2tbSzsrGwr62sq6qpqKalpKOioJ+enZyamZiWlZSTkZCPjYyLiYiHhYSCgYB+fXt6eHd1dHJxcG5sa2loZmVjYmBfXVtaWFdVU1JQTk1LSUhGREJBPz08Ojg2NDMxLy0rKigmJCIgHx0bGRcVExEPDQsJBwUDAf9/Px8PBwMBgEAgEAgEAgEAAQEBAQEBAQEBAQEA//////////////+AEAcAAQABAAEBAAEBAAEA/wD//wD//wD/AP+AKwcBAAEAAQD/AP8A/wD/AP8A/wABAAEAAQCARgcBAQEBAQD//////////////wABAQEBAQGAYQf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+AwODw+Pz+/xEAwAGxwj4E9cU+BfUKbwMKZ37+gCALI34LAiN+AwILGOsahhIDHBwcHPE9IN7BIRAAGVRdPgX1Cm8DCmcalhIjfAILfQIDAx0dHR3xPSDnIRgAGVRd8T0grskRAcAB6cI+BPUKbwMKZ37+gCALI34LAiN+AwILGOs+CvUahhIcHBwc8T0g9CN8Agt9AgMD8T0g0MkgIEZJTExFRCAgIFBPTFlHT05TIEhFTElDT1BURVJJTiBBQ1RJT04gIQDADgpwLHQsGhPWICI2ACwNIPE+oOoQyngBCQDlYmsJVF3hDMYKR3AsdCwaG9YgIjYALA0g8a/qEcrJ+hDK/jDI1gTqEMpHPqCQ/lA4Aj5QDgAM1ggw+3ghAcARBAB3xggZDSD5+hHKg+oRykf+UDgCPlAOAAzWCDD7eC4td9YIGQ0g+ckh9grzMf/PzVABr+Am4P/gD+BD4EL2SOBFPkDgQT4E4AfN9RM+CuoAAA4HeeBwJqCvIstsKPsNIPIh/v8yy30g+wEKABH1/yFpAc3kE+cCAVYAEQDBIVt2zeQTrwYYIWsOzYsUIYsOzaQUxwGwAxEAgCGhF8XlzeQT4cERAIjN5BMhAJgRAwABYMDHcc9yIwUg+BQdIPHN9RMhuxUGAc2WE82JEz5E4EGv4EU+A+D/+z4B6hLK4E0QAAB4zccTBSD6zZATxwEACFkhAIhzIwt4sSD5IQDHPv9FdyRwJCJ3JXclcCwg8x5/IQCYx3PPNgDL1DYIx3PLlCPLVCjuPoABDxARIAAhIpjF5XfL1HfLlDwZDSD1POEswQUg7D486jPLr+o0yz3qL8s+oOCCPgLqG8vNiRM+ROBBr+BFPgPg/68+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MAGEeRcvT/F5MAIvPIVvJrcBAAA+t7zLEbrLED6/vcsRu8sQPj+8P8sRuj/LEL0/yxG7P8sQeLHIeKHAebcgB3xiV31rX3jLH9L/HD5AlU97lW96lPUwAi88R6/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYV5Fy9P8XkwAi88hGcuQMMxHMsf0pcdPkCUT3qUZ3uV9TACLzxHr8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZyxHLF5QwAYTLEcsXlDABhMsRyxeUMAGEyxHLF5QwAYTLEcsXlDABhMsRyxeUMAGEyxHLF5QwAYTLEcsXlDABhHkXL0/xeTACLzyFbyZAwzEcyx/SoRt91r9PfZNvepT1MAIvPEevyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxnLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFeRcvT/F5MAIvPIRnLr/DMRz//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3q8MAVUZ3tdb3u90pdAfZNPepRfkTA+V3nLPy88g+CDPn+R5YdPbyYARCkpKQkBkVIJweV41kAXb3nWQB8fH+YPZ/CChGd55gcGB/YITwpP8INHLMl5S1+RV3nLPy88g+CDPneR5YdPbyYARCkpKQkBklsJweV41kAXb3nWQB8fH+YPZ/CChGd55gcGB/YITwpP8INHLMmVT3qUX5EwPld5yz8vPIPggz5/keWHT28mAEQpKSkJAR9BCcHleNZAF2951kAfHx/mD2fwgoRneeYHBgf2CE8KT/CDRyzJeUtfkVd5yz8vPIPggz53keWHT28mAEQpKSkJASBKCcHleNZAF2951kAfHx/mD2fwgoRneeYHBgf2CE8KT/CDRyzJfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkyX6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALMl+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASXJfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsyf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wHRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYt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uDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNyXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDcmDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDMlxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggzJxg+Hh+oawXovpl96obMiei+mX3qgszIkeRgAInAtJCJwLSQicC0kInAtJCJwLSQicC0kInAtJCJwLSQicC0kInAtJCJwLSQicC0kInAtJCJwLSQW/8n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+qqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMMM8AAEgASM8AzDAAhACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMM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cAkicAkicAkicAkicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCXIscAl7InAJInAJInAJInAJInAJInAJInAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAkicAkicAkicAlyLHAJeyJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJInAJInAJInAJcixwCXsicAkicAkicAkicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCXIscAl7InAJInAJInAJInAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAkicAkicAkicAkicAkicAkicAlyLHAJeyJwCSJwCSJwCSJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJcixwCXsicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCXIscAl7InAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAlyLHAJeyJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJcixwCXsicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCXIscAl7LCwly2XIJGjJycnJydE+t5LI4IXmB8RSRPCFHx8focjlzTJE4XkicCwicCwicCwicCwicCwicCwicCwicCzJ+ABUXWhHeZAfyx1nATNZCfCCMQCv/qAoAzEAvwH/AOlHPgeQVF1HDjOvyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxlHIbRXCeViaz7/AQ8Ayfoay2/6G8uFZ/4UIAU+/y0YBtbsIAU8LOoby3zqGsvNr2AhlEbNyhDwpMagV/Cjxn9f1SGXRs3KEPCkxqBn8KPGf2/RzTEcKAsf2hhZH9oYWcPERny6OAViV31rX+XNmkbh1Xu90sxFe9ZA4Ih9k0884Il6lF/ghjzgij2RMGvgh3nLPy88g+CF8IIBDwBvVHzWQBfLN6GFZ3rmBxdvGAjwij3KAETgivCJX/CGV/CFGASCHSgLy38g+Ffwh4LghR3NYkUY2nvgifCIg1/l5gf2CG8mB1Z7aB8fHx/LHR/LHeYDxkBnrx7/6XnghpPgh3vLPy88geCF8IIBDwBvVHzWQBfLN6GFZ3rmBxdv8Ilf8IZX8IXLfyAHV/CHgh0YAYLghc1iRfCKPcoAROCKGN171kDgiHuVTzzgiXqUX+CGPOCKPZEwa+CHecs/LzyD4IXwggEPAG9UfNZAF8s3oYVneuYHF28YCPCKPcoAROCK8Ilf8IZX8IUYBIIdKAvLfyD4V/CHguCFHc0qRhjae+CJ8IiTX+XmB/YQbyYHVntoHx8fH8sdH8sd5gPGQGc+/1jpeeCGk+CHe8s/LzyB4IXwggEPAG9UfNZAF8s3oYVneuYHF2/wiV/whlfwhct/IAdX8IeCHRgBguCFzSpG8Io9ygBE4IoY3UYAALoAAHzWQMhPHx8f5h9HeeYHKAsE/gUwBvUhylblBT4PkCHJRoRn5fCCZ69vyfCCZ69vIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIsnxAQ8APcqEVz0odj0oOj0idwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwksLCXLZSgCJGgidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwksLCXLZSgCJGgidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwksLCXLZSgCJGgidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkid8kicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAloyfgAVF3wgjEAr/6gKAMxAL8B/wDFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcVia/nJJgJ+4JovPOCYfcZAb37gl+Cbr+CZ4JzgneCePkDgn8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Aw==';
9780 // End of realtime.js file.