[pypy-svn] r53413 - in pypy/branch/gameboy-emulator/pypy/lang/gameboy: . test

cami at codespeak.net cami at codespeak.net
Sun Apr 6 00:48:07 CEST 2008


Author: cami
Date: Sun Apr  6 00:48:06 2008
New Revision: 53413

Modified:
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/cpu.py
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/interrupt.py
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/serial.py
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/sound.py
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_interrupt.py
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_timer.py
   pypy/branch/gameboy-emulator/pypy/lang/gameboy/timer.py
Log:
extended timer tests
cleaned up interrupt
adapted interrupt tests
introduced interrupt flag objects



Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/cpu.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/cpu.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/cpu.py	Sun Apr  6 00:48:06 2008
@@ -51,8 +51,7 @@
                 self.cpu.cycles += 1
         else:
             self.setHi(hi, useCycles)
-            self.setLo(lo, useCycles)
-            
+            self.setLo(lo, useCycles)   
     
     def reset(self):
         self.set(self.resetValue, None, False)
@@ -270,8 +269,6 @@
         if self.halted:
             val += 0x80
         return val
-    
-    
 
     def isZ(self):
         """ zero flag"""
@@ -306,31 +303,23 @@
 
     def isNotN(self):
         return not self.isN()
-    
-    
+       
     # Flags ............................................
-    
                     
     def setROM(self, banks):
-        self.rom = banks
-       
+        self.rom = banks       
             
     def emulate(self, ticks):
         self.cycles += ticks
-        self.interrupt()
+        self.handlePendingInterrupt()
         while (self.cycles > 0):
             self.execute()
 
      # Interrupts
-    def interrupt(self, address=None):
-        if address != None:
-            self.ime = False
-            self.call(address)
-            return
+    def handlePendingInterrupt(self):
         if self.halted:
             if (self.interrupt.isPending()):
                 self.halted = False
-                # Zerd no Densetsu
                 self.cycles -= 4
             elif (self.cycles > 0):
                 self.cycles = 0
@@ -338,21 +327,10 @@
             self.lowerPendingInterrupt()
             
     def lowerPendingInterrupt(self):
-        if (self.interrupt.isPending(constants.VBLANK)):
-            self.interrupt(0x40)
-            self.interrupt.lower(constants.VBLANK)
-        elif (self.interrupt.isPending(constants.LCD)):
-            self.interrupt(0x48)
-            self.interrupt.lower(constants.LCD)
-        elif (self.interrupt.isPending(constants.TIMER)):
-            self.interrupt(0x50)
-            self.interrupt.lower(constants.TIMER)
-        elif (self.interrupt.isPending(constants.SERIAL)):
-            self.interrupt(0x58)
-            self.interrupt.lower(constants.SERIAL)
-        elif (self.interrupt.isPending(constants.JOYPAD)):
-            self.interrupt(0x60)
-            self.interrupt.lower(constants.JOYPAD)
+        for flag in self.interrupt.interruptFlags:
+            if flag.isPending():
+                self.call(flag.callCode, disableIme=True)
+                flag.setPending(False)
 
      # Execution
     def fetchExecute(self):
@@ -383,6 +361,11 @@
             data = self.memory.read(self.pc.get())
         self.pc.inc() # 2 cycles
         return data
+    
+    def fetchDoubleAddress(self):
+        lo = self.fetch() # 1 cycle
+        hi = self.fetch() # 1 cycle
+        return (hi << 8) + lo
         
     def fetchDoubleRegister(self, register):
         self.popDoubleRegister(CPU.fetch, register)
@@ -415,7 +398,9 @@
         self.cycles += 1
         
     # 4 cycles
-    def call(self, address):
+    def call(self, address, disableIME=False):
+        if disableIME:
+            self.ime = False
         self.push(self.pc.getHi()) # 2 cycles
         self.push(self.pc.getLo()) # 2 cycles
         self.pc.set(address)       # 1 cycle
@@ -457,24 +442,23 @@
         s = self.a.get() + getter();
         if self.f.cFlag:
             s +=1
-        self.f.reset()
-        self.f.zeroFlagAdd(s)
+        self.carryFlagFinish(getter, 0x10)
         if s >= 0x100:
             self.f.cFlag= True
-        if ((s ^ self.a.get() ^ getter()) & 0x10) != 0:
-            self.f.hFlag= True
-        self.a.set(s & 0xFF)  # 1 cycle
 
     # 1 cycle
     def subtractWithCarry(self, getter, setter=None):
         s = self.a.get() - getter();
         if self.f.cFlag:
             s -= 1
-        self.f.reset()
-        self.f.nFlag = True
-        self.f.zeroFlagAdd(s)
+        self.carryFlagFinish(getter, 0x10)
         if (s & 0xFF00) != 0:
             self.f.cFlag = True
+        self.f.nFlag = True
+        
+    def carryFlagFinish(self, getter):
+        self.f.reset()
+        self.f.zeroFlagAdd(s)
         if ((s ^ self.a.get() ^ getter()) & 0x10) != 0:
             self.f.hFlag = True
         self.a.set(s & 0xFF)  # 1 cycle
@@ -547,7 +531,6 @@
         self.f.cFlagAdd(self.a.get(), 0x80, reset=True)
         self.a.set(((self.a.get() & 0x7F) << 1) + ((self.a.get() & 0x80) >> 7))
 
-
     # 1 cycle
     def rotateLeft(self, getter, setter):
         s = ((getter() & 0x7F) << 1)
@@ -634,9 +617,7 @@
         
      # LD A,(nnnn), 4 cycles
     def storeFetchedMemoryInA(self):
-        lo = self.fetch() # 1 cycle
-        hi = self.fetch() # 1 cycle
-        self.a.set(self.read(hi, lo))  # 1+1 cycles
+        self.a.set(self.read(self.fetchDoubleAddress()))  # 1+1 + 2 cycles
 
     # 2 cycles
     def writeAAtBCAddress(self):
@@ -657,18 +638,14 @@
 
      # LD (nnnn),SP  5 cycles
     def load_mem_SP(self):
-        lo = self.fetch() # 1 cycle
-        hi = self.fetch() # 1 cycle
-        address = (hi << 8) + lo
+        address = self.fetchDoubleAddress() # 2 cycles
         self.write(address, self.sp.getLo())  # 2 cycles
         self.write((address + 1), self.sp.getHi()) # 2 cycles
         self.cycles += 1
 
      # LD (nnnn),A  4 cycles
-    def storeAatFetchedAddress(self):
-        lo = self.fetch() # 1 cycle
-        hi = self.fetch() # 1 cycle
-        self.write((hi << 8) + lo, self.a.get()) # 2 cycles
+    def storeAAtFetchedAddress(self):
+        self.write(self.fetchDoubleAddress(), self.a.get()) # 2 cycles
 
      # LDH A,(nn) 3 cycles
     def storeMemoryAtExpandedFetchAddressInA(self):
@@ -715,7 +692,7 @@
         self.sp.set(self.hl.get()) # 1 cycle
         self.cycles -= 1
 
-    #
+    # CPA
     def complementA(self):
         self.a.set(self.a.get() ^ 0xFF)
         self.f.nFlag = True
@@ -793,9 +770,8 @@
 
      # JP nnnn, 4 cycles
     def unconditionalJump(self):
-        lo = self.fetch() # 1 cycle
-        hi = self.fetch() # 1 cycle
-        self.pc.set(hi,lo) # 2 cycles
+        self.pc.set(self.fetchDoubleAddress()) # 1+2 cycles
+        self.cycles -= 1
 
      # JP cc,nnnn 3,4 cycles
     def conditionalJump(self, cc):
@@ -818,9 +794,7 @@
     
      # CALL nnnn, 6 cycles
     def unconditionalCall(self):
-        lo = self.fetch() # 1 cycle
-        hi = self.fetch() # 1 cycle
-        self.call((hi << 8) + lo)  # 4 cycles
+        self.call(self.fetchDoubleAddress())  # 4+2 cycles
 
      # CALL cc,nnnn, 3,6 cycles
     def conditionalCall(self, getter):
@@ -847,12 +821,8 @@
      # RETI 4 cycles
     def returnFormInterrupt(self):
         self.ret() # 4 cycles
-         # enable interrupts
-        self.ime = True
-        # execute next instruction
-        self.execute(self.fetch())
-        # check pending interrupts
-        self.interrupt()
+        self.enableInterrupts()
+        self.cycles += 1
 
      # RST nn 4 cycles
     def restart(self, nn):
@@ -860,19 +830,15 @@
 
      # DI/EI 1 cycle
     def disableInterrupts(self):
-        # disable interrupts
         self.ime = False
         self.cycles -= 1; 
 
     # 1 cycle
     def enableInterrupts(self): 
-        # enable interrupts
         self.ime = True
         self.cycles -= 1
-        # execute next instruction
         self.execute(self.fetch())
-        # check pending interrupts
-        self.interrupt()
+        self.handlePendingInterrupt()
 
      # HALT/STOP
     def halt(self):
@@ -880,8 +846,7 @@
         # emulate bug when interrupts are pending
         if (not self.ime and self.interrupt.isPending()):
             self.execute(self.memory.read(self.pc.get()))
-        # check pending interrupts
-        self.interrupt()
+        self.handlePendingInterrupt()
 
     # 0 cycles
     def stop(self):
@@ -957,7 +922,7 @@
     return result
 
 # OPCODE TABLES ---------------------------------------------------------------
-     
+                        
 FIRST_ORDER_OP_CODES = [
     (0x00, CPU.nop),
     (0x08, CPU.load_mem_SP),
@@ -983,7 +948,7 @@
     (0xF3, CPU.disableInterrupts),
     (0xFB, CPU.enableInterrupts),
     (0xE2, CPU.writeAAtExpandedCAddress),
-    (0xEA, CPU.storeAatFetchedAddress),
+    (0xEA, CPU.storeAAtFetchedAddress),
     (0xF2, CPU.storeExpandedCinA),
     (0xFA, CPU.storeFetchedMemoryInA),
     (0xC3, CPU.unconditionalJump),

Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/interrupt.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/interrupt.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/interrupt.py	Sun Apr  6 00:48:06 2008
@@ -1,5 +1,24 @@
 from pypy.lang.gameboy import constants
 
+
+class InterruptFlag(object):
+    
+    def __init__(self, _reset, mask, callCode):
+        self._reset = _reset
+        self.mask = mask
+        self.callCode = callCode
+        self.reset()
+        
+    def reset(self):
+        self._isPending = self._reset
+        
+    def isPending(self):
+        return self._isPending
+    
+    def setPending(self, _isPending):
+        self._isPending = _isPending
+    
+
 class Interrupt(object):
     """
     PyBoy GameBoy (TM) Emulator
@@ -8,23 +27,50 @@
     """
     
     def __init__(self):
+        self.createInterruptFlags()
+        self.createFlagList()
+        self.createFlagMaskMapping()
         self.reset()
-
+        
+    def createInterruptFlags(self):
+        self.vBlank = InterruptFlag(True, constants.VBLANK, 0x40)
+        self.lcd = InterruptFlag(False, constants.LCD, 0x48)
+        self.timer = InterruptFlag(False, constants.TIMER, 0x50)
+        self.serial = InterruptFlag(False, constants.SERIAL, 0x58)
+        self.joypad = InterruptFlag(False, constants.JOYPAD, 0x60)
+        
+    def createFlagList(self):
+        self.interruptFlags = [
+            self.vBlank, self.lcd, 
+            self.timer, self.serial,
+            self.joypad
+        ]
+
+    def createFlagMaskMapping(self):
+        self.maskMapping = {}
+        for flag in self.interruptFlags:
+            self.maskMapping[flag.mask] = flag
+        
     def reset(self):
-        self.enable = 0
-        self.flag = constants.VBLANK
+        self.enable = False
+        for flag in self.interruptFlags:
+            flag.reset()
 
     def isPending(self, mask=None):
+        if not self.enable:
+            return False
         if mask==None:
-            return (self.enable & self.flag) != 0
+            return self.vBlank.isPending()
+        elif self.vBlank.isPending():
+            return self.maskMapping[mask].isPending()
         else:
-            return (self.enable & self.flag & mask) != 0
+            return False
 
     def raiseInterrupt(self, mask):
-        self.flag |= mask
+        self.maskMapping[mask].setPending(True)
 
     def lower(self, mask):
-        self.flag &= ~mask
+        self.maskMapping[mask].setPending(False)
 
     def write(self, address, data):
         if  address == constants.IE:
@@ -40,13 +86,21 @@
         return 0xFF
 
     def getInterruptEnable(self):
-        return self.enable
-
-    def getInterruptFlag(self):
-        return 0xE0 | self.flag
+        return int(self.enable)
 
     def setInterruptEnable(self, data):
-        self.enable = data
+        self.enable = bool(data)
+        
+    def getInterruptFlag(self):
+        flag = 0x00
+        for interruptFlag in self.interruptFlags:
+            if interruptFlag.isPending():
+                flag |= interruptFlag.mask
+        return 0xE0 | flag
 
     def setInterruptFlag(self, data):
-        self.flag = data
+        for flag in self.interruptFlags:
+            if (data & flag.mask) != 0:
+                flag.setPending(True)
+            else:
+                flag.setPending(False)

Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/serial.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/serial.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/serial.py	Sun Apr  6 00:48:06 2008
@@ -19,14 +19,14 @@
         return self.cycles
 
     def emulate(self, ticks):
-        if ((self.sc & 0x81) == 0x81):
-            self.cycles -= ticks
-            if (self.cycles <= 0):
-                self.sb = 0xFF
-                self.sc &= 0x7F
-                self.cycles = constants.SERIAL_IDLE_CLOCK
-                self.interrupt.raiseInterrupt(constants.SERIAL)
-
+        if ((self.sc & 0x81) != 0x81):
+            return
+        self.cycles -= ticks
+        if (self.cycles <= 0):
+            self.sb = 0xFF
+            self.sc &= 0x7F
+            self.cycles = constants.SERIAL_IDLE_CLOCK
+            self.interrupt.raiseInterrupt(constants.SERIAL)
 
     def setSerialData(self, data):
         self.sb = data

Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/sound.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/sound.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/sound.py	Sun Apr  6 00:48:06 2008
@@ -82,19 +82,15 @@
         self.generateNoiseTables()
         self.reset()
 
-
     def start(self):
         self.driver.start()
 
-
     def stop(self):
         self.driver.stop()
 
-
     def cycles(self):
         return self.cycles
 
-
     def emulate(self, ticks):
         self.cycles -= ticks
         while (self.cycles <= 0):
@@ -107,8 +103,6 @@
                 self.frames %= constants.SOUND_CLOCK
 
             self.cycles += constants.GAMEBOY_CLOCK / constants.SOUND_CLOCK
-    
-
 
     def reset(self):
         self.cycles = constants.GAMEBOY_CLOCK / constants.SOUND_CLOCK
@@ -197,10 +191,8 @@
 
         elif (address >= constants.AUD3WAVERAM and address <= constants.AUD3WAVERAM + 0x3F):
             return self.getAudio3WavePattern(address)
-
         return 0xFF
 
-
     def write(self, address, data):
         if address==constants.NR10:
             self.setAudio1Sweep(data)
@@ -252,7 +244,6 @@
         elif (address >= constants.AUD3WAVERAM and address <= constants.AUD3WAVERAM + 0x3F):
             self.setAudio3WavePattern(address, data)
 
-
     def updateAudio(self):
         if ((self.nr52 & 0x80) == 0):
             return
@@ -265,10 +256,8 @@
         if ((self.nr52 & 0x08) != 0):
             self.updateAudio4()
 
-
     def mixAudio(self,buffer, length):
-        for index in range(0, length):
-            buffer[index] = 0
+        buffer = [0]*length
         if ((self.nr52 & 0x80) == 0):
             return
         if ((self.nr52 & 0x01) != 0):
@@ -280,38 +269,30 @@
         if ((self.nr52 & 0x08) != 0):
             self.mixAudio4(buffer, length)
 
-
      # Audio Channel 1
     def getAudio1Sweep(self):
         return self.nr10
 
-
     def getAudio1Length(self):
         return self.nr11
 
-
     def getAudio1Envelope(self):
         return self.nr12
 
-
     def getAudio1Frequency(self):
         return self.nr13
 
-
     def getAudio1Playback(self):
         return self.nr14
 
-
     def setAudio1Sweep(self, data):
         self.nr10 = data
         self.audio1SweepLength = (constants.SOUND_CLOCK / 128) * ((self.nr10 >> 4) & 0x07)
 
-
     def setAudio1Length(self, data):
         self.nr11 = data
         self.audio1Length = (constants.SOUND_CLOCK / 256) * (64 - (self.nr11 & 0x3F))
 
-
     def setAudio1Envelope(self, data):
         self.nr12 = data
         if ((self.nr14 & 0x40) != 0):
@@ -323,12 +304,10 @@
         else:
             self.audio1Volume = (self.audio1Volume + 2) & 0x0F
 
-
     def setAudio1Frequency(self, data):
         self.nr13 = data
         self.audio1Frequency = self.frequencyTable[self.nr13 + ((self.nr14 & 0x07) << 8)]
 
-
     def setAudio1Playback(self, data):
         self.nr14 = data
         self.audio1Frequency = self.frequencyTable[self.nr13
@@ -340,7 +319,6 @@
             self.audio1SweepLength = (constants.SOUND_CLOCK / 128) * ((self.nr10 >> 4) & 0x07)
             self.audio1Volume = self.nr12 >> 4
             self.audio1EnvelopeLength = (constants.SOUND_CLOCK / 64) * (self.nr12 & 0x07)
-    
 
     def updateAudio1(self):
         if ((self.nr14 & 0x40) != 0 and self.audio1Length > 0):
@@ -375,7 +353,6 @@
                         self.nr52 &= ~0x01
             
                 self.audio1SweepLength += (constants.SOUND_CLOCK / 128) * ((self.nr10 >> 4) & 0x07)
-        
 
     def mixAudio1(self, buffer, length):
         wavePattern = 0x18
@@ -399,29 +376,23 @@
                 if ((self.nr51 & 0x01) != 0):
                     buffer[index + 1] += self.audio1Volume
         
-    
      # Audio Channel 2
     def getAudio2Length(self):
         return self.nr21
 
-
     def getAudio2Envelope(self):
         return self.nr22
 
-
     def getAudio2Frequency(self):
         return self.nr23
 
-
     def getAudio2Playback(self):
         return self.nr24
 
-
     def setAudio2Length(self, data):
         self.nr21 = data
         self.audio2Length = (constants.SOUND_CLOCK / 256) * (64 - (self.nr21 & 0x3F))
 
-
     def setAudio2Envelope(self, data):
         self.nr22 = data
         if ((self.nr24 & 0x40) == 0):
@@ -432,13 +403,11 @@
             else:
                 self.audio2Volume = (self.audio2Volume + 2) & 0x0F
 
-
     def setAudio2Frequency(self, data):
         self.nr23 = data
         self.audio2Frequency = self.frequencyTable[self.nr23\
                 + ((self.nr24 & 0x07) << 8)]
 
-
     def setAudio2Playback(self, data):
         self.nr24 = data
         self.audio2Frequency = self.frequencyTable[self.nr23\
@@ -450,8 +419,6 @@
             self.audio2Volume = self.nr22 >> 4
             self.audio2EnvelopeLength = (constants.SOUND_CLOCK / 64) * (self.nr22 & 0x07)
     
-
-
     def updateAudio2(self):
         if ((self.nr24 & 0x40) != 0 and self.audio2Length > 0):
             self.audio2Length-=1
@@ -468,7 +435,6 @@
                     self.audio2Volume-=1
                 self.audio2EnvelopeLength += (constants.SOUND_CLOCK / 64) * (self.nr22 & 0x07)
         
-
     def mixAudio2(self, buffer, length):
         wavePattern = 0x18
         if (self.nr21 & 0xC0) == 0x00:
@@ -491,48 +457,38 @@
                 if ((self.nr51 & 0x02) != 0):
                     buffer[index + 1] += self.audio2Volume
 
-
      # Audio Channel 3
     def getAudio3Enable(self):
         return self.nr30
 
-
     def getAudio3Length(self):
         return self.nr31
 
-
     def getAudio3Level(self):
         return self.nr32
 
-
     def getAudio4Frequency(self):
         return self.nr33
 
-
     def getAudio3Playback(self):
         return self.nr34
 
-
     def setAudio3Enable(self, data):
         self.nr30 = data & 0x80
         if ((self.nr30 & 0x80) == 0):
             self.nr52 &= ~0x04
 
-
     def setAudio3Length(self, data):
         self.nr31 = data
         self.audio3Length = (constants.SOUND_CLOCK / 256) * (256 - self.nr31)
 
-
     def setAudio3Level(self, data):
         self.nr32 = data
 
-
     def setAudio3Frequency(self, data):
         self.nr33 = data
         self.audio3Frequency = self.frequencyTable[((self.nr34 & 0x07) << 8) + self.nr33] >> 1
 
-
     def setAudio3Playback(self, data):
         self.nr34 = data
         self.audio3Frequency = self.frequencyTable[((self.nr34 & 0x07) << 8) + self.nr33] >> 1
@@ -541,24 +497,18 @@
             if ((self.nr34 & 0x40) != 0 and self.audio3Length == 0):
                 self.audio3Length = (constants.SOUND_CLOCK / 256) * (256 - self.nr31)
     
-
-
     def setAudio3WavePattern(self, address, data):
-        #TODO convert to byte
         self.audio3WavePattern[address & 0x0F] = data
 
-
     def getAudio3WavePattern(self, address):
         return self.audio3WavePattern[address & 0x0F] & 0xFF
 
-
     def updateAudio3(self):
         if ((self.nr34 & 0x40) != 0 and self.audio3Length > 0):
             self.audio3Length-=1
             if (self.audio3Length <= 0):
                 self.nr52 &= ~0x04
 
-
     def mixAudio3(self, buffer, length):
         wavePattern = 2
         if (self.nr32 & 0x60) == 0x00:
@@ -583,29 +533,23 @@
             if ((self.nr51 & 0x04) != 0):
                 buffer[index + 1] += sample
     
-
      # Audio Channel 4
     def getAudio4Length(self):
         return self.nr41
 
-
     def getAudio4Envelope(self):
         return self.nr42
 
-
     def getAudio4Polynomial(self):
         return self.nr43
 
-
     def getAudio4Playback(self):
         return self.nr44
 
-
     def setAudio4Length(self, data):
         self.nr41 = data
         self.audio4Length = (constants.SOUND_CLOCK / 256) * (64 - (self.nr41 & 0x3F))
 
-
     def setAudio4Envelope(self, data):
         self.nr42 = data
         if ((self.nr44 & 0x40) == 0):
@@ -616,7 +560,6 @@
             else:
                 self.audio4Volume = (self.audio4Volume + 2) & 0x0F
 
-
     def setAudio4Polynomial(self, data):
         self.nr43 = data
         if ((self.nr43 >> 4) <= 12):
@@ -624,7 +567,6 @@
         else:
             self.audio4Frequency = 0
 
-
     def setAudio4Playback(self, data):
         self.nr44 = data
         if ((self.nr44 & 0x80) != 0):
@@ -634,8 +576,6 @@
             self.audio4Volume = self.nr42 >> 4
             self.audio4EnvelopeLength = (constants.SOUND_CLOCK / 64) * (self.nr42 & 0x07)
             self.audio4Index = 0
-    
-
 
     def updateAudio4(self):
         if ((self.nr44 & 0x40) != 0 and self.audio4Length > 0):
@@ -651,7 +591,6 @@
                 elif (self.audio4Volume > 0):
                     self.audio4Volume-=1
                 self.audio4EnvelopeLength += (constants.SOUND_CLOCK / 64) * (self.nr42 & 0x07)
-        
     
     def mixAudio4(self, buffer, length):
         for index in range(0, length, 2):
@@ -676,28 +615,22 @@
                 if ((self.nr51 & 0x08) != 0):
                     buffer[index + 1] += self.audio4Volume
 
-
      # Output Control
     def getOutputLevel(self):
         return self.nr50
 
-
     def getOutputTerminal(self):
         return self.nr51
 
-
     def getOutputEnable(self):
         return self.nr52
 
-
     def setOutputLevel(self, data):
         self.nr50 = data
 
-
     def setOutputTerminal(self, data):
         self.nr51 = data
 
-
     def setOutputEnable(self, data):
         self.nr52 = (self.nr52 & 0x7F) | (data & 0x80)
         if ((self.nr52 & 0x80) == 0x00):
@@ -741,7 +674,6 @@
             self.noiseStep15Table[index >> 5] |= (polynomial & 1) << (index & 31)
             
             
-            
 # SOUND DRIVER -----------------------------------------------------------------
 
 class SoundDriver(object):
@@ -749,7 +681,6 @@
     def __init__(self):
         self.enabled = True
     
-    
     def isEnabled(self):
         return self.enabled
     

Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_interrupt.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_interrupt.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_interrupt.py	Sun Apr  6 00:48:06 2008
@@ -7,15 +7,15 @@
 
 
 
-def test_rest():
+def test_reset():
     interrupt = get_interrupt()
     assert interrupt.enable == 0
-    assert interrupt.flag  == constants.VBLANK
+    assert interrupt.getInterruptFlag()  == 0xE0 | constants.VBLANK
     interrupt.enable = 1
     interrupt.flag = ~constants.VBLANK
     interrupt.reset()
     assert interrupt.enable == 0
-    assert interrupt.flag  == constants.VBLANK
+    assert interrupt.getInterruptFlag()  == 0xE0 | constants.VBLANK
     
     
 def test_is_pending():
@@ -23,34 +23,41 @@
     assert interrupt.isPending() == False
     assert interrupt.isPending(0x00) == False
     interrupt.setInterruptEnable(True)
-    assert interrupt.isPending() == True
+    assert interrupt.isPending()
     
     
-def test_raise_interrupt():
+def test_is_pending_common_masks():
     interrupt = get_interrupt()
-    value = 0x12
-    mask = 0xAA
-    interrupt.flag = value
-    assert interrupt.flag == value
-    interrupt.raiseInterrupt(mask)
-    assert interrupt.flag == value|mask
+    for flag in interrupt.interruptFlags:
+        interrupt.reset()
+        interrupt.enable = True
+        assert interrupt.vBlank.isPending()
+        flag.setPending(True)
+        assert interrupt.isPending(flag.mask)
+        
     
-def test_lower():
+def test_raise_lower_interrupt():
     interrupt = get_interrupt()
-    value = 0x12
-    mask = 0xAA
-    interrupt.flag = value
-    assert interrupt.flag == value
-    interrupt.lower(mask)
-    assert interrupt.flag == value & (~mask)
+    masks= [constants.LCD, constants.TIMER, 
+            constants.JOYPAD, constants.SERIAL]
+    interrupt.setInterruptEnable(True)
+    interrupt.vBlank.setPending(True)
+    for mask in masks:
+        interrupt.raiseInterrupt(mask)
+        assert interrupt.maskMapping[mask].isPending() == True
+        assert interrupt.isPending(mask) == True
+        interrupt.lower(mask)
+        assert interrupt.isPending(mask) == False
     
 def test_read_write():
     interrupt = get_interrupt()
-    value = 0x12
+    value = 1
     interrupt.write(constants.IE, value)
     assert interrupt.enable == value
     assert interrupt.read(constants.IE) == value
-    value+=1
+    
+    interrupt.reset()
+    value = constants.LCD
     interrupt.write(constants.IF, value)
-    assert interrupt.flag == value
+    assert interrupt.getInterruptFlag() == 0xE0 | value
     assert interrupt.read(constants.IF) == 0xE0 | value

Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_timer.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_timer.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/test/test_timer.py	Sun Apr  6 00:48:06 2008
@@ -5,11 +5,7 @@
 
 
 def get_timer():
-    return Timer(get_timer_interrupt())
-
-def get_timer_interrupt():
-    return Interrupt()
-    
+    return Timer(Interrupt())
 
     
 # ------------------------------------------------------------------------------
@@ -47,26 +43,93 @@
     timer.reset()
     
     
-    
-    
-def test_setTimerControl():
+def test_getTimerControl():
     timer = get_timer()
     value = 0x12
     timer.write(constants.TAC, value)
     assert timer.getTimerControl() == 0xF8 | value 
     assert timer.read(constants.TAC) == 0xF8 |value
+
+def test_setTimerControl():
+    timer = get_timer()
+    value = 0x12
+    timer.setTimerControl(value)
+    assert timer.tac == value
+    assert timer.timerCycles == constants.TIMER_CLOCK[value & 0x03]
+    assert timer.timerClock  == constants.TIMER_CLOCK[value & 0x03]
+    timer.reset()
+    timer.tac = value+1
+    timer.timerClock = 0
+    timer.timerCycles = 0
+    timer.setTimerControl(value+1)
+    assert timer.tac == value+1
+    assert timer.timerClock == 0
+    assert timer.timerClock == 0
     
+def test_read_write_Divider():
+    timer = get_timer()
+    value = 0x12
+    timer.div = value
+    assert timer.getDivider() == timer.div
+    # divider resets on write
+    timer.setDivider(value)
+    assert timer.getDivider() == 0
     
 def test_cycles():
-    py.test.skip("not yet implemented")
     timer = get_timer()
+    value = 10
+    timer.dividerCycles = value
+    assert timer.cycles() == timer.dividerCycles
+    timer.tac = 0x04
+    timer.timerCycles = value-1
+    timer.timerCycles = value
+    assert timer.cycles() == timer.timerCycles
     
-
-def test_emulateDivider():
-    py.test.skip("not yet implemented")
+def test_emulateDivider_normal():
     timer = get_timer()
+    value = 2
+    timer.timerCycles = 0
+    timer.emulateTimer(value)
     
-
-def test_emulateTimer():
-    py.test.skip("not yet implemented")
-    timer = get_timer()
\ No newline at end of file
+def test_test_emulateDivider_zero():
+    timer = get_timer()
+    value = 2
+    timer.timerCycles = value
+    timer.emulateTimer(value)
+    assert timer.timerCycles == value
+    
+def test_emulateTimer_tac_return():
+    timer = get_timer()
+    timer.tac = 0
+    timer.timerCycles = -10
+    cycles = timer.timerCycles
+    timer.emulateTimer(10)
+    assert timer.timerCycles == cycles
+    
+def test_emulateTimer_timer_cycles_return():
+    timer = get_timer()
+    timer.tac = 0x04
+    value = 10
+    timer.timerCycles = value+1
+    cycles = timer.timerCycles
+    timer.emulateTimer(value)
+    assert timer.timerCycles == 1
+    
+    timer = get_timer()
+    timer.tac = 0x04
+    
+    
+def test_emulateTimer_interrupt():
+    timer = get_timer()
+    ticks = 0
+    timer.tac = 0x04
+    timer.tima = -1
+    # raise an interupt as we pass 0
+    assert timer.interrupt.isPending(constants.TIMER) == False
+    timer.timerCycles = -timer.timerClock+1
+    timer.emulateTimer(ticks)
+    assert timer.timerCycles == 1
+    assert timer.tima == timer.tma
+    assert timer.interrupt.timer.isPending()
+    
+    
\ No newline at end of file

Modified: pypy/branch/gameboy-emulator/pypy/lang/gameboy/timer.py
==============================================================================
--- pypy/branch/gameboy-emulator/pypy/lang/gameboy/timer.py	(original)
+++ pypy/branch/gameboy-emulator/pypy/lang/gameboy/timer.py	Sun Apr  6 00:48:06 2008
@@ -4,6 +4,7 @@
 Timer and Divider
 """
 from pypy.lang.gameboy import constants
+from math import ceil
 
 class Timer(object):
 
@@ -15,7 +16,7 @@
         self.div = 0
         self.dividerCycles = constants.DIV_CLOCK
         self.tima = self.tma = self.tac = 0x00
-        self.timerCycles = self.timerClock = constants.TIMER_CLOCK[self.tac & 0x03]
+        self.timerCycles = self.timerClock = constants.TIMER_CLOCK[0]
 
     def write(self,  address, data):
         if address==constants.DIV:
@@ -61,7 +62,7 @@
 
     def setTimerControl(self,  data):
         if ((self.tac & 0x03) != (data & 0x03)):
-            self.timerCycles = self.timerClock = constants.TIMER_CLOCK[data & 0x03]
+            self.timerClock =  self.timerCycles = constants.TIMER_CLOCK[data & 0x03]
         self.tac = data
 
     def cycles(self):
@@ -75,20 +76,30 @@
 
     def emulateDivider(self,  ticks):
         self.dividerCycles -= ticks
-        while (self.dividerCycles <= 0):
-            self.div = (self.div + 1) & 0xFF
-            self.dividerCycles += constants.DIV_CLOCK
-    
+        if self.dividerCycles > 0:
+            return
+        count = int(ceil(-1.0*self.dividerCycles / constants.DIV_CLOCK))
+        self.div = (self.div + count) & 0xFF
+        self.dividerCycles += constants.DIV_CLOCK*count
+            
     def emulateTimer(self,  ticks):
-        if ((self.tac & 0x04) != 0):
-            self.timerCycles -= ticks
-            while (self.timerCycles <= 0):
-                self.tima = (self.tima + 1) & 0xFF
-                self.timerCycles += self.timerClock
-                if (self.tima == 0x00):
-                    self.tima = self.tma
-                    self.interrupt.raiseInterrupt(constants.TIMER)
-    
+        if (self.tac & 0x04) == 0:
+            return
+        self.timerCycles -= ticks
+        if self.timerCycles > 0:
+            return
+        count = int(ceil(-1.0*self.timerCycles / self.timerClock))
+        self.timaZeroPassCheck(count)
+        self.tima = (self.tima + count) & 0xFF
+        self.timerCycles += self.timerClock * count
+
+    def timaZeroPassCheck(self, count):
+        if (self.tima < 0) and (self.tima + count >= 0):
+            self.tima = self.tma - count
+            print "raising"
+            self.interrupt.raiseInterrupt(constants.TIMER)
+            print self.interrupt.timer.isPending(), self.interrupt.isPending(constants.TIMER)
+        
 # CLOCK DRIVER -----------------------------------------------------------------
 
 class ClockDriver(object):



More information about the Pypy-commit mailing list