1964js/coffee/interrupts.coffee
2018-07-11 10:53:30 -04:00

591 lines
27 KiB
CoffeeScript

###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