###1964js - JavaScript/HTML5 port of 1964 - N64 emulator Copyright (C) 2012 Joel Middendorf This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.### #1964cpp treats consts.MI_INTR_MASK_REG_R as a separate memory location. Not sure that's right. #jslint bitwise: true, devel: true, todo: true #globals consts, log, C1964jsVideoHLE #SP_STATUS_REG read flags `/** @const */ SP_STATUS_HALT = 0x0001` `/** @const */ SP_STATUS_BROKE = 0x0002` `/** @const */ SP_STATUS_DMA_BUSY = 0x0004` `/** @const */ SP_STATUS_DMA_FULL = 0x0008` `/** @const */ SP_STATUS_IO_FULL = 0x0010` `/** @const */ SP_STATUS_SSTEP = 0x0020` `/** @const */ SP_STATUS_INTR_BREAK = 0x0040` `/** @const */ SP_STATUS_YIELD = 0x0080` `/** @const */ SP_STATUS_YIELDED = 0x0100` `/** @const */ SP_STATUS_TASKDONE = 0x0200` `/** @const */ SP_STATUS_SIG3 = 0x0400` `/** @const */ SP_STATUS_SIG4 = 0x0800` `/** @const */ SP_STATUS_SIG5 = 0x1000` `/** @const */ SP_STATUS_SIG6 = 0x2000` `/** @const */ SP_STATUS_SIG7 = 0x4000` #SP_STATUS_REG write flags `/** @const */ SP_CLR_HALT = 0x0000001` `/** @const */ SP_SET_HALT = 0x0000002` `/** @const */ SP_CLR_BROKE = 0x0000004` `/** @const */ SP_CLR_INTR = 0x0000008` `/** @const */ SP_SET_INTR = 0x0000010` `/** @const */ SP_CLR_SSTEP = 0x0000020` `/** @const */ SP_SET_SSTEP = 0x0000040` `/** @const */ SP_CLR_INTR_BREAK = 0x0000080` `/** @const */ SP_SET_INTR_BREAK = 0x0000100` `/** @const */ SP_CLR_YIELD = 0x0000200` `/** @const */ SP_SET_YIELD = 0x0000400` `/** @const */ SP_CLR_YIELDED = 0x0000800` `/** @const */ SP_SET_YIELDED = 0x0001000` `/** @const */ SP_CLR_TASKDONE = 0x0002000` `/** @const */ SP_SET_TASKDONE = 0x0004000` `/** @const */ SP_CLR_SIG3 = 0x0008000` `/** @const */ SP_SET_SIG3 = 0x0010000` `/** @const */ SP_CLR_SIG4 = 0x0020000` `/** @const */ SP_SET_SIG4 = 0x0040000` `/** @const */ SP_CLR_SIG5 = 0x0080000` `/** @const */ SP_SET_SIG5 = 0x0100000` `/** @const */ SP_CLR_SIG6 = 0x0200000` `/** @const */ SP_SET_SIG6 = 0x0400000` `/** @const */ SP_CLR_SIG7 = 0x0800000` `/** @const */ SP_SET_SIG7 = 0x1000000` currentHack = 0 C1964jsInterrupts = (core, cp0) -> "use strict" @delayNextInterrupt = false @setException = (exception, causeFlag, pc, isFromDelaySlot) -> #log('set exception'); cp0[consts.CAUSE] |= exception cp0[consts.CAUSE] |= causeFlag return @processException = (pc, isFromDelaySlot) -> # we don't want to process interrupts immediately if @delayNextInterrupt is true core.m[0] = -156250 @delayNextInterrupt = false return return false if (cp0[consts.STATUS] & consts.IE) is 0 if (cp0[consts.STATUS] & consts.EXL) isnt 0 #log "nested exception" return false cp0[consts.CAUSE] &= 0xFFFFFF83 #Clear exception code flags cp0[consts.STATUS] |= consts.EXL if isFromDelaySlot is true #log "Exception happens in CPU delay slot, pc=" + pc cp0[consts.CAUSE] |= consts.BD cp0[consts.EPC] = pc - 4 # throw 'interrupt'; else cp0[consts.CAUSE] &= ~consts.BD cp0[consts.EPC] = pc #throw 'interrupt'; core.flushDynaCache() if core.doOnce is 0 core.doOnce = 1 core.p[0] = 0x80000180 true @triggerCompareInterrupt = (pc, isFromDelaySlot) -> @setException consts.EXC_INT, consts.CAUSE_IP8, pc, isFromDelaySlot #if core.interval is 3 #don't process immediately #core.m[0] = -156250 return @triggerPIInterrupt = (pc, isFromDelaySlot) -> @setFlag core.memory.miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_PI value = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (value & consts.MI_INTR_MASK_PI) isnt 0 return @triggerSPInterrupt = (pc, isFromDelaySlot) -> @setFlag core.memory.miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_SP value = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (value & consts.MI_INTR_MASK_SP) isnt 0 return @triggerVIInterrupt = (pc, isFromDelaySlot) -> @setFlag core.memory.miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_VI value = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (value & consts.MI_INTR_MASK_VI) isnt 0 return @triggerSIInterrupt = (pc, isFromDelaySlot) -> @setFlag core.memory.miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_SI value = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (value & consts.MI_INTR_MASK_SI) isnt 0 return @triggerAIInterrupt = (pc, isFromDelaySlot) -> @setFlag core.memory.miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_AI value = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (value & consts.MI_INTR_MASK_AI) isnt 0 return @triggerDPInterrupt = (pc, isFromDelaySlot) -> @setFlag core.memory.miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_DP value = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (value & consts.MI_INTR_MASK_DP) isnt 0 return @triggerRspBreak = -> @setFlag core.memory.spReg1Uint8Array, consts.SP_STATUS_REG, consts.SP_STATUS_TASKDONE | consts.SP_STATUS_BROKE | consts.SP_STATUS_HALT value = core.memory.getInt32 core.memory.spReg1Uint8Array, consts.SP_STATUS_REG, core.memory.spReg1Uint32Array @triggerSPInterrupt 0, false if (value & consts.SP_STATUS_INTR_BREAK) isnt 0 return @clearMIInterrupt = (flag) -> @clrFlag core.memory.miUint8Array, consts.MI_INTR_REG, flag miIntrMaskReg = core.memory.getInt32 core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array cp0[consts.CAUSE] &= ~consts.CAUSE_IP3 if (miIntrMaskReg & (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint32Array))) is 0 return #if((cp0[CAUSE] & cp0[STATUS] & SR_IMASK) == 0) # CPUNeedToCheckInterrupt = FALSE; @readVI = (offset) -> switch offset when consts.VI_CURRENT_REG #hack for berney demo currentHack = 0 if (currentHack += 1) is 625 # triggerVIInterrupt(pc, isFromDelaySlot); #warning: need to refactor. triggerVIInterrupt #can service an interrupt immediately without setting rt[i] #return currentHack; return ((core.memory.getInt32(core.memory.viUint8Array, offset, core.memory.viUint32Array) & 0xfffffffe) + currentHack) | 0 else #log "unhandled video interface for vi offset: " + offset return core.memory.getInt32 core.memory.viUint8Array, offset, core.memory.viUint32Array @writeVI = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.VI_ORIGIN_REG core.memory.setInt32 core.memory.viUint8Array, offset, value, core.memory.viUint32Array #var c = document.getElementById("Canvas"); #var ctx = c.getContext("2d"); #repaint(ctx,ImDat,value & 0x00FFFFFF); #alert('origin changed' + dec2hex(value)); when consts.VI_CURRENT_REG @clearMIInterrupt consts.MI_INTR_VI core.memory.setInt32 core.memory.viUint8Array, offset, value, core.memory.viUint32Array when consts.VI_INTR_REG core.memory.setInt32 core.memory.viUint8Array, offset, value, core.memory.viUint32Array else core.memory.setInt32 core.memory.viUint8Array, offset, value, core.memory.viUint32Array return #log('unhandled vi write: ' + offset); @writePI = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.PI_WR_LEN_REG core.memory.setInt32 core.memory.piUint8Array, offset, value, core.memory.piUint32Array core.dma.copyCartToDram pc, isFromDelaySlot when consts.PI_RD_LEN_REG core.memory.setInt32 core.memory.piUint8Array, offset, value, core.memory.piUint32Array core.dma.copyDramToCart pc, isFromDelaySlot when consts.PI_DRAM_ADDR_REG core.memory.setInt32 core.memory.piUint8Array, offset, value, core.memory.piUint32Array when consts.PI_CART_ADDR_REG core.memory.setInt32 core.memory.piUint8Array, offset, value, core.memory.piUint32Array when consts.PI_STATUS_REG @writePIStatusReg value, pc, isFromDelaySlot else core.memory.setInt32 core.memory.piUint8Array, offset, value, core.memory.piUint32Array #log "unhandled pi write: " + offset return @writeSI = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.SI_DRAM_ADDR_REG core.memory.setInt32 core.memory.siUint8Array, offset, value, core.memory.siUint32Array when consts.SI_STATUS_REG @writeSIStatusReg value, pc, isFromDelaySlot when consts.SI_PIF_ADDR_RD64B_REG core.memory.setInt32 core.memory.siUint8Array, offset, value, core.memory.siUint32Array core.dma.copySiToDram pc, isFromDelaySlot when consts.SI_PIF_ADDR_WR64B_REG core.memory.setInt32 core.memory.siUint8Array, offset, value, core.memory.siUint32Array core.dma.copyDramToSi pc, isFromDelaySlot else core.memory.setInt32 core.memory.siUint8Array, offset, value, core.memory.siUint32Array #log "unhandled si write: " + offset return @readSI = (offset) -> switch offset when consts.SI_STATUS_REG @readSIStatusReg() return core.memory.getInt32 core.memory.siUint8Array, offset, core.memory.siUint32Array else #log "unhandled si read: " + offset return core.memory.getInt32 core.memory.siUint8Array, offset, core.memory.siUint32Array return @readSIStatusReg = -> if (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint32Array) & consts.MI_INTR_SI) isnt 0 @setFlag core.memory.siUint8Array, consts.SI_STATUS_REG, consts.SI_STATUS_INTERRUPT else @clrFlag core.memory.siUint8Array, consts.SI_STATUS_REG, consts.SI_STATUS_INTERRUPT return @readAI = (offset) -> switch offset when consts.AI_LEN_REG #todo: implement AI_LEN_REG -- how many bytes unconsumed.. core.kfi -= 1 if core.kfi is 0 core.kfi = 512 #todo: this comes from viewport? @clrFlag core.memory.aiUint8Array, consts.AI_STATUS_REG, consts.AI_STATUS_FIFO_FULL @triggerAIInterrupt 0, false #checkInterrupts(); return 0 return 2048 #return kfi; #return getInt32(aiUint8Array, offset); when consts.AI_STATUS_REG return core.memory.getInt32 core.memory.aiUint8Array, offset, core.memory.aiUint32Array else #log "unhandled read ai reg " + offset return core.memory.getInt32 core.memory.aiUint8Array, offset, core.memory.aiUint32Array return @writeAI = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.AI_DRAM_ADDR_REG core.memory.setInt32 core.memory.aiUint8Array, offset, value, core.memory.aiUint32Array when consts.AI_LEN_REG core.memory.setInt32 core.memory.aiUint8Array, offset, value, core.memory.aiUint32Array core.dma.copyDramToAi pc, isFromDelaySlot when consts.AI_STATUS_REG @clearMIInterrupt consts.MI_INTR_AI when consts.AI_DACRATE_REG # log("todo: write AI_DACRATE_REG"); core.memory.setInt32 core.memory.aiUint8Array, offset, value, core.memory.aiUint32Array when consts.AI_CONTROL_REG core.memory.setInt32 core.memory.aiUint8Array, offset, value & 1, core.memory.aiUint32Array else #log('unhandled write ai reg ' + offset); core.memory.setInt32 core.memory.aiUint8Array, offset, value, core.memory.aiUint32Array return @writeMI = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.MI_INIT_MODE_REG @writeMIModeReg value when consts.MI_INTR_MASK_REG @writeMIIntrMaskReg value, pc, isFromDelaySlot when consts.MI_VERSION_REG, consts.MI_INTR_REG #do nothing. read-only else core.memory.setInt32 core.memory.miUint8Array, offset, value, core.memory.miUint32Array #log "unhandled mips interface for mi offset: " + offset return @readSPReg1 = (offset) -> switch offset when consts.SP_STATUS_REG return core.memory.getInt32 core.memory.spReg1Uint8Array, offset, core.memory.spReg1Uint32Array when consts.SP_SEMAPHORE_REG temp = core.memory.getInt32(core.memory.aiUint8Array, offset, core.memory.aiUint32Array) core.memory.setInt32 core.memory.spReg1Uint8Array, offset, 1, core.memory.spReg1Uint32Array return temp else #log "unhandled read sp reg1 " + offset return core.memory.getInt32 core.memory.spReg1Uint8Array, offset, core.memory.spReg1Uint32Array return @writeSPReg1 = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.SP_STATUS_REG @writeSPStatusReg value, pc, isFromDelaySlot when consts.SP_SEMAPHORE_REG core.memory.setInt32 core.memory.spReg1Uint8Array, offset, 0, core.memory.spReg1Uint32Array when consts.SP_WR_LEN_REG core.memory.setInt32 core.memory.spReg1Uint8Array, offset, value, core.memory.spReg1Uint32Array core.dma.copySpToDram pc, isFromDelaySlot when consts.SP_RD_LEN_REG core.memory.setInt32 core.memory.spReg1Uint8Array, offset, value, core.memory.spReg1Uint32Array core.dma.copyDramToSp pc, isFromDelaySlot else core.memory.setInt32 core.memory.spReg1Uint8Array, offset, value, core.memory.spReg1Uint32Array #log "unhandled sp reg1 write: " + offset return @writeSPReg2 = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.SP_PC_REG #log "writing sp pc: " + value core.memory.setInt32 core.memory.spReg2Uint8Array, offset, value & 0x00000FFC, core.memory.spReg2Uint32Array else core.memory.setInt32 core.memory.spReg2Uint8Array, offset, value, core.memory.spReg2Uint32Array #log "unhandled sp reg2 write: " + offset return #Set flag for memory register @setFlag = (where, offset, flag) -> value = core.memory.getUint32(where, offset) value |= flag core.memory.setUint32 where, offset, value return #Clear flag for memory register @clrFlag = (where, offset, flag) -> value = core.memory.getUint32(where, offset) value &= ~flag core.memory.setUint32 where, offset, value return @writeMIModeReg = (value) -> if value & consts.MI_SET_RDRAM @setFlag core.memory.miUint8Array, consts.MI_INIT_MODE_REG, consts.MI_MODE_RDRAM else @clrFlag core.memory.miUint8Array, consts.MI_INIT_MODE_REG, consts.MI_MODE_RDRAM if value & consts.MI_CLR_RDRAM if value & consts.MI_SET_INIT @setFlag core.memory.miUint8Array, consts.MI_INIT_MODE_REG, consts.MI_MODE_INIT else @clrFlag core.memory.miUint8Array, consts.MI_INIT_MODE_REG, consts.MI_MODE_INIT if value & consts.MI_CLR_INIT if value & consts.MI_SET_EBUS @setFlag core.memory.miUint8Array, consts.MI_INIT_MODE_REG, consts.MI_MODE_EBUS else @clrFlag core.memory.miUint8Array, consts.MI_INIT_MODE_REG, consts.MI_MODE_EBUS if value & consts.MI_CLR_EBUS #this.clrFlag(miUint8Array, consts.MI_INTR_REG, consts.MI_INTR_DP); #setInt32(miUint8Array, MI_INIT_MODE_REG, core.memory.getInt32(miUint8Array, MI_INIT_MODE_REG, miUint32Array)|(value&0x7f), miUint32Array); @clearMIInterrupt consts.MI_INTR_DP if value & consts.MI_CLR_DP_INTR return @writeMIIntrMaskReg = (value, pc, isFromDelaySlot) -> if value & consts.MI_INTR_MASK_SP_SET @setFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_SP else @clrFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_SP if value & consts.MI_INTR_MASK_SP_CLR if value & consts.MI_INTR_MASK_SI_SET @setFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_SI else @clrFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_SI if value & consts.MI_INTR_MASK_SI_CLR if value & consts.MI_INTR_MASK_AI_SET @setFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_AI else @clrFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_AI if value & consts.MI_INTR_MASK_AI_CLR if value & consts.MI_INTR_MASK_VI_SET @setFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_VI else @clrFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_VI if value & consts.MI_INTR_MASK_VI_CLR if value & consts.MI_INTR_MASK_PI_SET @setFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_PI else @clrFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_PI if value & consts.MI_INTR_MASK_PI_CLR if value & consts.MI_INTR_MASK_DP_SET @setFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_DP else @clrFlag core.memory.miUint8Array, consts.MI_INTR_MASK_REG, consts.MI_INTR_DP if value & consts.MI_INTR_MASK_DP_CLR #Check MI interrupt again. This is important, otherwise we will lose interrupts. #Trigger an MI interrupt since we don't know what it is. @setException consts.EXC_INT, consts.CAUSE_IP3, pc, isFromDelaySlot if (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_MASK_REG, core.memory.miUint32Array) & 0x0000003F & core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint32Array)) isnt 0 return @writeSIStatusReg = (value, pc, isFromDelaySlot) -> #Clear SI interrupt unconditionally @clearMIInterrupt(consts.MI_INTR_SI); #wrong! @clrFlag core.memory.siUint8Array, consts.SI_STATUS_REG, consts.SI_STATUS_INTERRUPT return @writeSPStatusReg = (value, pc, isFromDelaySlot) -> tempSr = core.memory.getInt32(core.memory.spReg1Uint8Array, consts.SP_STATUS_REG, core.memory.spReg1Uint32Array) tempSr &= ~consts.SP_STATUS_BROKE if value & SP_CLR_BROKE if value & SP_SET_INTR @triggerSPInterrupt pc, isFromDelaySlot #to use else if here is a possible bux fix (what is this?..this looks weird). # No. this else causes freezing. # else @clearMIInterrupt consts.MI_INTR_SP if value & SP_CLR_INTR if value & SP_SET_SSTEP tempSr |= SP_STATUS_SSTEP else tempSr &= ~SP_STATUS_SSTEP if value & SP_CLR_SSTEP if value & SP_SET_INTR_BREAK tempSr |= SP_STATUS_INTR_BREAK else tempSr &= ~SP_STATUS_INTR_BREAK if value & SP_CLR_INTR_BREAK if value & SP_SET_YIELD tempSr |= SP_STATUS_YIELD else tempSr &= ~SP_STATUS_YIELD if value & SP_CLR_YIELD if value & SP_SET_YIELDED tempSr |= SP_STATUS_YIELDED else tempSr &= ~SP_STATUS_YIELDED if value & SP_CLR_YIELDED if value & SP_SET_TASKDONE tempSr |= SP_STATUS_TASKDONE else tempSr &= ~SP_STATUS_YIELDED if value & SP_CLR_YIELDED if value & SP_SET_SIG3 tempSr |= SP_STATUS_SIG3 else tempSr &= ~SP_STATUS_SIG3 if value & SP_CLR_SIG3 if value & SP_SET_SIG4 tempSr |= SP_STATUS_SIG4 else tempSr &= ~SP_STATUS_SIG4 if value & SP_CLR_SIG4 if value & SP_SET_SIG5 tempSr |= SP_STATUS_SIG5 else tempSr &= ~SP_STATUS_SIG5 if value & SP_CLR_SIG5 if value & SP_SET_SIG6 tempSr |= SP_STATUS_SIG6 else tempSr &= ~SP_STATUS_SIG6 if value & SP_CLR_SIG6 if value & SP_SET_SIG7 tempSr |= SP_STATUS_SIG7 else tempSr &= ~SP_STATUS_SIG7 if value & SP_CLR_SIG7 if value & SP_SET_HALT tempSr |= SP_STATUS_HALT core.memory.setInt32 core.memory.spReg1Uint8Array, consts.SP_STATUS_REG, tempSr, core.memory.spReg1Uint32Array else if value & SP_CLR_HALT if (tempSr & SP_STATUS_BROKE) is 0 #bugfix. tempSr &= ~SP_STATUS_HALT core.memory.setInt32 core.memory.spReg1Uint8Array, consts.SP_STATUS_REG, tempSr, core.memory.spReg1Uint32Array spDmemTask = core.memory.getInt32(core.memory.spMemUint8Array, consts.SP_DMEM_TASK, core.memory.spMemUint32Array) #log "SP Task triggered. SP_DMEM_TASK=" + spDmemTask @runSPTask spDmemTask else core.memory.setInt32 core.memory.spReg1Uint8Array, consts.SP_STATUS_REG, tempSr, core.memory.spReg1Uint32Array return #Added by Rice, 2001.08.10 #SP_STATUS_REG |= SP_STATUS_HALT; //why? # this.setFlag(spReg1Uint8Array, consts.SP_STATUS_REG, consts.SP_STATUS_HALT); //why? @writeDPCStatusReg = (value, pc, isFromDelaySlot) -> @clrFlag core.memory.dpcUint8Array, consts.DPC_STATUS_REG, consts.DPC_STATUS_XBUS_DMEM_DMA if value & consts.DPC_CLR_XBUS_DMEM_DMA @setFlag core.memory.dpcUint8Array, consts.DPC_STATUS_REG, consts.DPC_STATUS_XBUS_DMEM_DMA if value & consts.DPC_SET_XBUS_DMEM_DMA @clrFlag core.memory.dpcUint8Array, consts.DPC_STATUS_REG, consts.DPC_STATUS_FREEZE if value & consts.DPC_CLR_FREEZE @setFlag core.memory.dpcUint8Array, consts.DPC_STATUS_REG, consts.DPC_STATUS_FREEZE if value & consts.DPC_SET_FREEZE @clrFlag core.memory.dpcUint8Array, consts.DPC_STATUS_REG, consts.DPC_STATUS_FLUSH if value & consts.DPC_CLR_FLUSH @setFlag core.memory.dpcUint8Array, consts.DPC_STATUS_REG, consts.DPC_STATUS_FLUSH if value & consts.DPC_SET_FLUSH return # #if(value & DPC_CLR_TMEM_REG) (DPC_TMEM_REG) = 0; #if(value & DPC_CLR_PIPEBUSY_REG) (DPC_PIPEBUSY_REG) = 0; #if(value & DPC_CLR_BUFBUSY_REG) (DPC_BUFBUSY_REG) = 0; #if(value & DPC_CLR_CLOCK_REG) (DPC_CLOCK_REG) = 0; # @writeDPC = (offset, value, pc, isFromDelaySlot) -> switch offset when consts.DPC_STATUS_REG @writeDPCStatusReg value, pc, isFromDelaySlot when consts.DPC_START_REG core.memory.setInt32 core.memory.dpcUint8Array, offset, value, core.memory.dpcUint32Array when consts.DPC_END_REG core.memory.setInt32 core.memory.dpcUint8Array, offset, value, core.memory.dpcUint32Array @processRDPList() when consts.DPC_CLOCK_REG, consts.DPC_BUFBUSY_REG, consts.DPC_PIPEBUSY_REG, consts.DPC_TMEM_REG break else core.memory.setInt32 core.memory.dpcUint8Array, offset, value, core.memory.dpcUint32Array #log "unhandled dpc write: " + offset return @writePIStatusReg = (value, pc, isFromDelaySlot) -> @clearMIInterrupt consts.MI_INTR_PI if value & consts.PI_STATUS_CLR_INTR if value & consts.PI_STATUS_RESET #When PIC is reset, if PIC happens to be busy, an interrupt will be generated #as PIC returns to idle. Otherwise, no interrupt will be generated and PIC #remains idle. if core.memory.getInt32(core.memory.piUint8Array, consts.PI_STATUS_REG, core.memory.piUint32Array) & (consts.PI_STATUS_IO_BUSY | consts.PI_STATUS_DMA_BUSY) #Is PI busy? #Reset the PIC core.memory.setInt32 core.memory.piUint8Array, consts.PI_STATUS_REG, 0, core.memory.piUint32Array #Reset finished, set PI Interrupt @triggerPIInterrupt pc, isFromDelaySlot else #Reset the PIC core.memory.setInt32 core.memory.piUint8Array, consts.PI_STATUS_REG, 0, core.memory.piUint32Array return #Does not actually write into the PI_STATUS_REG @runSPTask = (spDmemTask) -> # throw 'todo: run hle task'; switch spDmemTask when consts.BAD_TASK #log "bad sp task" break when consts.GFX_TASK if core.videoHLE is null or core.videoHLE is `undefined` if core.isLittleEndian is 1 and core.useByteCompatibilityMode is false ###* * @const ### core.videoHLE = new C1964jsVideoHLEle(core, core.webGL.gl) else ###* * @const ### core.videoHLE = new C1964jsVideoHLE(core, core.webGL.gl) repeatDList = document.getElementById("repeatDList") core.settings.repeatDList = false core.settings.repeatDList = true if repeatDList isnt null and repeatDList.checked if core.terminate is false core.videoHLE.processDisplayList() if core.settings.repeatDList is true core.stopEmulatorAndCleanup() @interval = setInterval(=> core.videoHLE.processDisplayList() @triggerRspBreak 0, false return , 1000) else @triggerRspBreak 0, false when consts.SND_TASK @processAudioList() @triggerRspBreak 0, false when consts.JPG_TASK @processJpegTask() @triggerRspBreak 0, false else #log "unhandled sp task: " + spDmemTask break @checkInterrupts() return @processAudioList = -> #log "todo: process Audio List" #just clear flags now to get the gfx tasks :) #see UpdateFifoFlag in 1964cpp's AudioLLE main.cpp. @clrFlag core.memory.aiUint8Array, consts.AI_STATUS_REG, consts.AI_STATUS_FIFO_FULL #@interrupts.triggerAIInterrupt 0, false #core.kfi = 512 return @processJpegTask = -> #log "todo: processJpegTask" return @processRDPList = -> #log "todo: process rdp list" return @checkInterrupts = -> @triggerDPInterrupt 0, false if (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint32Array) & consts.MI_INTR_DP) isnt 0 @triggerAIInterrupt 0, false if (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint32Array) & consts.MI_INTR_AI) isnt 0 @triggerSIInterrupt 0, false if (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint8Array) & consts.MI_INTR_SI) isnt 0 @triggerRspBreak 0, false if (core.memory.getInt32(core.memory.miUint8Array, consts.MI_INTR_REG, core.memory.miUint32Array) & consts.MI_INTR_SP) isnt 0 #if ((core.memory.getInt32(miUint8Array, consts.MI_INTR_REG, miUint32Array) & consts.MI_INTR_VI) !== 0) # this.triggerVIInterrupt(0, false); @setException consts.EXC_INT, 0, core.p, false if (cp0[consts.CAUSE] & cp0[consts.STATUS] & 0x0000FF00) isnt 0 #do not process interrupts here as we don't have support for #interrupts in delay slots. process them in the main runLoop. return return this #hack global space until we export classes properly #node.js uses exports; browser uses this (window) root = exports ? self root.C1964jsInterrupts = C1964jsInterrupts