Commits

Amaury Forgeot d'Arc committed 7a32d1f

merge revisions 55322:55728

Comments (0)

Files changed (157)

pypy/config/config.py

             value = self.convert_from_cmdline(value)
             self.config.setoption(self.option._name, value, who='cmdline')
         except ConfigError, e:
+            # This OptionValueError is going to exit the translate.py process.
+            # Now is the last chance to print the warnings, which might give
+            # more information...  hack.
+            import sys
+            for warning in self.config.get_warnings():
+                print >> sys.stderr, warning
             raise optparse.OptionValueError(e.args[0])
 
     def help_default(self):

pypy/config/pypyoption.py

      "recparser", "symbol", "_random", "__pypy__"]))
 
 
+# --allworkingmodules
 working_modules = default_modules.copy()
 working_modules.update(dict.fromkeys(
     ["_socket", "unicodedata", "mmap", "fcntl",
-      "rctime" , "select", "zipimport",
+      "rctime" , "select", "zipimport", "_lsprof",
      "crypt", "signal", "dyngram", "_rawffi", "termios", "zlib",
      "struct", "md5", "sha", "bz2", "_minimal_curses", "cStringIO"]
 ))

pypy/config/translationoption.py

                  requires={
                      "shadowstack": [("translation.gctransformer", "framework")],
                      "llvmgc": [("translation.gctransformer", "framework"),
-                                ("translation.backend", "llvm")],
+                                ("translation.backend", "llvm"),
+                                ("translation.thread", False)],
                      "asmgcc": [("translation.gctransformer", "framework"),
-                                ("translation.backend", "c")],
+                                ("translation.backend", "c"),
+                                ("translation.thread", False)],
                     },
                  suggests={
                      "shadowstack": [("translation.gc", "generation")],
                      "asmgcc": [("translation.gc", "generation")],
                  }),
     BoolOption("thread", "enable use of threading primitives",
-               default=False, cmdline="--thread",
-               requires=[("translation.gc", "boehm")]),
+               default=False, cmdline="--thread"),
     BoolOption("verbose", "Print extra information", default=False),
     BoolOption("debug", "Record extra annotation information",
                cmdline="-d --debug", default=False),

pypy/doc/_ref.txt

 .. _`pypy/annotation/model.py`: ../../pypy/annotation/model.py
 .. _`bin/`: ../../pypy/bin
 .. _`config/`: ../../pypy/config
+.. _`pypy/config/pypyoption.py`: ../../pypy/config/pypyoption.py
 .. _`doc/`: ../../pypy/doc
 .. _`doc/config/`: ../../pypy/doc/config
 .. _`doc/discussion/`: ../../pypy/doc/discussion

pypy/doc/config/objspace.usemodules._lsprof.txt

+Use the '_lsprof' module. 

pypy/doc/config/translation.backendopt.coalloc.txt

-turn allocations into coallocations when appropriate. Requires the use of a
-generational GC. See the paper `Finding your Cronies`_.
-
-.. _`Finding your Cronies`: http://www.cs.utexas.edu/~sammy/cronies-oopsla-2004.pdf

pypy/doc/cpython_differences.txt

 Differences related to garbage collection strategies
 ----------------------------------------------------
 
-XXX: write me please
+Most of the garbage collectors used or implemented by PyPy are not based on
+reference counting, so the objects are not freed instantly when they are no
+longer reachable.  The most obvious effect of this is that files are not
+promptly closed when they go out of scope.  For files that are opened for
+writing, data can be left sitting in their output buffers for a while, making
+the on-disk file appear empty or truncated.
 
+Fixing this is essentially not possible without forcing a
+reference-counting approach to garbage collection.  The effect that you
+get in CPython has clearly been described as a side-effect of the
+implementation and not a language design decision: programs relying on
+this are basically bogus.  It would anyway be insane to try to enforce
+CPython's behavior in a language spec, given that it has no chance to be
+adopted by Jython or IronPython (or any other port of Python to Java or
+.NET, like PyPy itself).
 
-Subclasses of builtin ``dict`` objects
---------------------------------------
+There are a few extra implications for the difference in the GC.  Most
+notably, if an object has a __del__, the __del__ is never called more
+than once in PyPy; but CPython will call the same __del__ several times
+if the object is resurrected and dies again.  The __del__ methods are
+called in "the right" order if they are on objects pointing to each
+other, as in CPython, but unlike CPython, if there is a dead cycle of
+objects referencing each other, their __del__ methods are called anyway;
+CPython would instead put them into the list ``garbage`` of the ``gc``
+module.  More information is available on the blog `[1]`__ `[2]`__.
 
-When you pass an instance of a subclass of ``dict`` to the
-``dict.update`` method, CPython simply ignores potentially overridden
-methods, such as ``keys()`` or ``__getitem__()``; on the other hand,
-PyPy correctly calls the overridden versions of the methods.
+.. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-1.html
+.. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-2.html
 
-For example, the following code prints ``42`` on PyPy but ``foo``
-on CPython::
+The built-in function ``id()`` returns numbers that are not addresses
+for most of PyPy's garbage collectors.
+This is most visible in the default repr: a typical PyPy object can
+pretend to be located ``at 0x00000009``.  This is just its ``id()``, not
+its real address (because the physical address can change).
+
+Note that if you have a long chain of objects, each with a reference to
+the next one, and each with a __del__, PyPy's GC will perform badly.  On
+the bright side, in most other cases, benchmarks have shown that PyPy's
+GCs perform much better than CPython's.
+
+
+Subclasses of built-in types
+----------------------------
+
+Officially, CPython has no rule at all for when exactly
+overriden method of subclasses of built-in types get
+implicitly called or not.  As an approximation, these methods
+are never called by other built-in methods of the same object.
+For example, an overridden ``__getitem__()`` in a subclass of
+``dict`` will not be called by e.g. the built-in ``get()``
+method.
+
+The above is true both in CPython and in PyPy.  Differences
+can occur about whether a built-in function or method will
+call an overridden method of *another* object than ``self``.
+In PyPy, they are generally always called, whereas not in
+CPython.  For example, in PyPy, ``dict1.update(dict2)``
+considers that ``dict2`` is just a general mapping object, and
+will thus call overridden ``keys()``  and ``__getitem__()``
+methods on it.  So the following code prints ``42`` on PyPy
+but ``foo`` on CPython::
 
     >>>> class D(dict):
     ....     def __getitem__(self, key):
     >>>> print d1['a']
     42
 
-Comparison differencies
+
+Ignored exceptions
 -----------------------
 
-When custom \_\_eq\_\_ function on object (or any other rich comparison
-method) raises an exception, we don't swallow the exception and instead
-report it to user.
+In many corner cases, CPython can silently swallow exceptions.
+The precise list of when this occurs is rather long, even
+though most cases are very uncommon.  The most well-known
+places are custom rich comparison methods (like \_\_eq\_\_);
+dictionary lookup; calls to some built-in functions like
+isinstance().
 
+Unless this behavior is clearly present by design and
+documented as such (as e.g. for hasattr()), in most cases PyPy
+lets the exception propagate instead.
+

pypy/doc/discussion/standalone-howto.txt

-========================================================
-HOWTO: compile RPython code into a standalone executable
-========================================================
-
-(NOTE: you should first read the `FAQ entries`_ about Using the PyPy
-translation tool chain.  This document is a quick introduction to the
-interactive way to compile your own RPython code.  Keep in mind though
-that if you write a larger RPython program, the best and most flexible
-way to compile it is not as described below, but by writing a target
-file as described in the `FAQ entries`_.)
-
-========================================
-
-First, see the note above.
-Next, understand the restrictions on RPython_ code.
-Pay close attention to the description of tuples and 
-dicts. 
-
-Take this example program::
-
-    import os
-    
-    def main(argv):
-        os.write(1, "Hello world!\n")
-    
-        return 0
-
-To compile::
-
-    from pypy.translator.interactive import Translation
-    t = Translation(main, standalone=True, gc='ref')
-    
-    t.source(backend='c')
-    path = t.compile()
-    print path
-
-The path is the location of the executable.
-
-To see the translation in motion, try removing
-the ``argv`` argument to main, or the ``return 0``.
-
-Type inference happens in the Annotator_.
-Keep this in mind as you write RPython code.
-After annotation the low level code generation
-(the implementation of the types)
-happens in the RTyper_.
-
-These steps can be spelled out explicitly::
-
-    t.annotate()
-    t.rtype()
-    t.source(backend='c')
-    path = t.compile()
-
-After the ``annotate()`` or ``rtype()`` call
-you can view the resulting flow graph with
-a pygame/dot based graphing tool::
-
-    t.annotate()
-    t.view()
-    t.rtype()
-    t.view()
-
-Here are some debugging tips:
-
-- make sure the program runs before you try and compile it. 
-  The semantics of RPython compiled code should be the same as regular python.
-- try assert'ing things in your code, for example ``assert isinstance(num, int)``,
-  this can provide hints to the translation process that can help pinpoint the 
-  problem.
-
-RPython is tricky! 
-
-Take this example::
-
-    def abs(num):
-        if num < 0:
-            num = -num
-        return num
-    
-If you want to use this function with
-different argument types (eg. ``int`` and ``float``)
-the translation will fail. In order
-to generate a different function for each argument
-type we need to set an attribute::
-
-    abs._annspecialcase_ = "specialize:argtype(0)"
-
-As another example::
-
-    def sum(l):
-        total = 0
-        for v in l:
-            total += v
-        return total
-    
-    sum._annspecialcase_ = "specialize:argtype(0)"
-
-Now we can sum with different kinds of lists, eg.
-``sum([1,2,3])`` and ``sum([1.0,2.0,3.0])``.
-
-    
-.. _`FAQ Entries`: ../faq.html#pypy-translation-tool-chain
-.. _`RPython`: ../coding-guide.html#restricted-python
-.. _`Annotator`: ../dynamic-language-translation.html#annotator
-.. _`RTyper`: ../dynamic-language-translation.html#rtyper
-

pypy/doc/download.txt

 Download one of the following release files: 
 =============================================
 
+:warning:
+
+    the 1.0 release is out of date.  We strongly recommend that you
+    use the latest stable version.  See `getting started`_.
+
+.. _`getting started`: getting-started.html#get-via-subversion
+
 PyPy 1.0 Sources:
 -----------------
 
 At the moment you need CPython 2.4 (with ctypes 0.9.9.6 or newer) or
 CPython 2.5 for the translation process.
 
-Currently (due to time restrictions) we are not trying hard to support
-PyPy in a 64 bit environment.  While things seem to mostly work, a few
-modules won't work on 64 bit machines, such as ``bz2``.
+PyPy also basically works in a 64-bit Linux environment.
 
 ------------------------------------------------
 Which Python version (2.x?) does PyPy implement?
 
 PyPy currently aims to be fully compatible with Python 2.4. That means that
 it contains the standard library of Python 2.4 and that it supports 2.4
-features (such as decorators) but not the 2.5 features (with statement, the ternary
-operator).  The 2.5 features will probably be eventually supported, the most
-important reason why nobody is working on them is that we did not promise this
-to the EU and have currently enough other tasks.
+features (such as decorators).  The 2.5 features (e.g. the ``with`` statement,
+the ternary operator) are in progress.
 
 .. _threading:
 
 Do threads work?  What are the modules that work?
 -------------------------------------------------
 
-Operating system-level threads work in a limited way. If you enable the ``thread``
-module then PyPy will get support for GIL based threading. One limitation is
-that not that many IO operations actually release the GIL, which reduces the
-usefulness of threads. On the other hand, PyPy fully supports `stackless-like
+Operating system-level threads basically work. If you enable the ``thread``
+module then PyPy will get support for GIL based threading.
+Note that PyPy also fully supports `stackless-like
 microthreads`_ (although both cannot be mixed yet).
 
 As for other modules: The general rule of thumb is that pure-Python modules
-work, C extension modules don't. Some of the C extension modules of the standard
+work, C extension modules don't. However, many of the C extension modules
+of the standard
 library have been re-implemented in pure Python or as a mixed module (for some
-there were also older pure-Python versions available). A (probably incomplete)
-list:
+there were also older pure-Python versions available). The list of supported
+modules can be found as follows:
 
- * pure Python implementations: binascii, cmath, collections, cPickle,
-   cStringIO, datetime, functional, imp, itertools, md5, operator,
-   sha, struct
+ * pure Python implementations: all the modules found in the `pypy/lib/`_
+   directory
 
- * mixed module implementations: exceptions, sys, __builtin__, posix
-   _codecs, gc, _weakref, array, marshal, errno, math, _sre,  parser, symbol,
-   _random, socket, unicodedata, mmap, fcntl, time, select, bz2, crypt,
-   signal, readline (incomplete)
+ * mixed module implementations: all the modules listed in
+   ``essential_modules``, ``default_modules`` and ``working_modules``
+   in `pypy/config/pypyoption.py`_.
 
 
 .. _`stackless-like microthreads`: stackless.html
 rely heavily on CPython's C API which contains a lot of implementation details
 like reference counting, exact C-level object implementation and layout etc.
 
-Although if your module uses ctypes rather than C-level code, there is
-a hope -- you can try to write a mixed module (see next question).
+A module based on ctypes is a different matter -- we support these nowadays.
 
 The long-term answer might be different.  In principle, it should be possible
 for PyPy to support the CPython C API (or at least a large subset of its
 How do I write extension modules for PyPy?
 ------------------------------------------
 
-PyPy extension modules are written in the form of `mixed modules`_, so
-called because they can contain a mixture of compiled and interpreted
-Python code.  At the moment they all need to be translated together with the rest of PyPy.
+See `Writing extension modules for PyPy`__.
 
-.. _`mixed modules`: coding-guide.html#mixed-module-mechanism
+.. __: extending.html
+
 
 .. _`slower than CPython`:
 .. _`how fast is pypy`:
 CPython, the version of PyPy that still runs on top of CPython is slower
 by a factor of 2000. The first translated version was roughly 300 times
 slower than CPython, a number which we decreased release after release
-to the current point, where PyPy is only between 1.7 and 4 times slower
-than CPython.  Note that the speed heavily depends on the options
-enabled at compile time.
+to the current point, where PyPy is somewhere between 1 and 2, i.e. it
+is as fast as CPython in some cases, and up to twice as slow in other
+cases.  Note that the speed heavily depends on the options enabled at
+compile time.
 
 The integration of the work on the Just-In-Time compiler has just
-started; it can be `manually enabled`_ and gives good results on
-functions doing integer arithmetic (60 times faster than CPython,
-i.e. within 20% of recoding the function in C and compiling with ``gcc``
-without optimizations).
+started; it is not yet ready enough to give useful speed-ups.  See
+status__.
 
-.. _`manually enabled`: jit/status.html
+.. __: jit/status.html
 
 
 .. _`prolog and javascript`:
 up where.  In this way, you could compile the program into two copies of
 itself: a "fast" version and a "slow" version.  The former would contain
 many guards that allow it to fall back to the latter if needed.  That
-would be a wholly different project than PyPy, though.
+would be a wholly different project than PyPy, though.  (As far as we
+understand it, this is the approach that the LLVM__ group would like to
+see LLVM used for, so if you feel like working very hard and attempting
+something like this, check with them.)
+
+.. __: http://llvm.org/
 
 What PyPy contains is, on the one hand, an non-soft static type
 inferencer for RPython, which is a sublanguage that we defined just so
 an "entry point" function. The translation toolchain follows all calls
 recursively and discovers what belongs to the program and what not.
 
+-------------------------------------------------------------------------
+Can I use PyPy and RPython to compile smaller parts of my Python program?
+-------------------------------------------------------------------------
+
+No.  That would be possible, and we played with early attempts in that
+direction, but there are many delicate issues: for example, how the
+compiled and the non-compiled parts exchange data.  Supporting this in a
+nice way would be a lot of work.
+
+PyPy is certainly a good starting point for someone that would like to
+work in that direction.  Early attempts were dropped because they
+conflicted with refactorings that we needed in order to progress on the
+rest of PyPy; the currently active developers of PyPy have different
+priorities.  If someone wants to start working in that direction I
+imagine that he might get a (very little) bit of support from us,
+though.
+
+Alternatively, it's possible to write a mixed-module, i.e. an extension
+module for PyPy in RPython, which you can then import from your Python
+program when it runs on top of PyPy.  This is similar to writing a C
+extension module for CPython in term of investment of effort (without
+all the INCREF/DECREF mess, though).
+
 ------------------------------------------------------
 What's the ``"NOT_RPYTHON"`` I see in some docstrings?
 ------------------------------------------------------

pypy/doc/getting-started.txt

 ============== 
 
 .. _gettingpypy: 
-
-Downloading & running the PyPy 1.0 release 
---------------------------------------------
-
-*Note: the 1.0 release is out of date.  We strongly recommend that you
-use the latest stable version* (which you can `get via Subversion`_).
-
-Download one of the following release files: 
-
-*pypy-1.0*
-    
-    * `pypy-1.0.0.tar.bz2`_ (sources, unix line endings) or
-    * `pypy-1.0.0.tar.gz`_ (sources, unix line endings) or
-    * `pypy-1.0.0.zip`_ (sources, windows line-endings) or
-    * `pypy-1.0.0-win32.zip`_ (precompiled executables for windows)
-    * or get the `latest stable version via subversion`_.
- 
-After unpacking the source downloads you can change to the
-``pypy-1.0.0`` directory and execute the following command line::
-
-    python pypy/bin/py.py 
-
-This will give you a PyPy prompt, i.e. a very compliant Python
-interpreter implemented in Python.  PyPy passes around `98% of
-CPythons core language regression tests`_.  Because this invocation of
-PyPy still runs on top of CPython, it runs around 2000 times slower
-than the original CPython.
-Many extension modules are not enabled by default; to use them you need
-to pass ``--withmod-NAME`` arguments (for example, ``--withmod-_rawffi``
-is required to import our version of ctypes).
-
-This is probably not something you want to play with for too long,
-though, as it is really slow.
-Since the 0.7.0 release it is possible to use PyPy to `translate
-itself to lower level languages`_ after which it runs standalone, is not
-dependant on CPython anymore and becomes faster (within the same speed
-magnitude as CPython itself).
-
-If you are using the precompiled Windows executables, please look
-at the included ``README.txt`` on how to start already translated
-interpreters.  Note that the examples in the html documentation generally 
-assume that you have a py.py; with precompiled binaries, you need to 
-pick one with the matching features compiled in.
-
-.. _`98% of CPythons core language regression tests`: http://www2.openend.se/~pedronis/pypy-c-test/allworkingmodules/summary.html
-.. _`pypy-1.0.0.tar.bz2`: http://codespeak.net/download/pypy/pypy-1.0.0.tar.bz2
-.. _`pypy-1.0.0.zip`: http://codespeak.net/download/pypy/pypy-1.0.0.zip
-.. _`pypy-1.0.0.tar.gz`: http://codespeak.net/download/pypy/pypy-1.0.0.tar.gz
-.. _`pypy-1.0.0-win32.zip`: http://codespeak.net/download/pypy/pypy-1.0.0-win32.zip
-
 .. _`latest stable version via subversion`:   
 .. _`get via Subversion`:
 
 --------------------------------------------------
 
 If you want to play with the stable development PyPy version 
-you can check it out from the repository using subversion. Download 
-and install subversion_ if you don't already have it. Then you can
-issue on the command line (DOS box or terminal)::
+you can check it out from the repository using subversion.
+(Here are `old links`_ to the PyPy release 1.0 -- but don't
+use it, it is too far out of date.)
+
+.. _`old links`: download.html
+
+Download and install subversion_ if you don't already have it.  We have
+some `help on installing subversion`_ for PyPy.  Then you can issue on
+the command line (DOS box or terminal)::
 
     svn co http://codespeak.net/svn/pypy/dist pypy-dist 
 
     python pypy-dist/pypy/bin/py.py
 
 have fun :-) 
+This gives you a PyPy prompt, i.e. a very compliant Python
+interpreter implemented in Python.  PyPy passes around `98% of
+CPythons core language regression tests`_.  Because this invocation of
+PyPy still runs on top of CPython, it runs around 2000 times slower
+than the original CPython.
+Many extension modules are not enabled by default; to use them you need
+to pass ``--withmod-NAME`` arguments (for example, ``--withmod-_rawffi``
+is required to import our version of ctypes).
 
-We have some `help on installing subversion`_ for PyPy.
+This is probably not something you want to play with for too long,
+though, as it is really slow.  Instead, you should use PyPy to `translate
+itself to lower level languages`_ after which it runs standalone, is not
+dependant on CPython anymore and becomes faster (within the same speed
+magnitude as CPython itself).
+
+.. _`98% of CPythons core language regression tests`: http://www2.openend.se/~pedronis/pypy-c-test/allworkingmodules/summary.html
+
 Have a look at `interesting starting points`_ 
 for some guidance on how to continue. 
 
 
 .. _`windows document`: windows.html
 
-You can
-translate the PyPy's whole of Python interpreter to low level C code. This is
-the largest and
-ultimate example of source that our translation toolchain can process.
-If you don't need threads, the most standard variant nowadays is::
+You can translate the whole of PyPy's Python interpreter to low level C
+code.  This is the largest and ultimate example of RPython program that
+our translation toolchain can process.  The most standard variant
+nowadays is::
 
     cd pypy/translator/goal
-    python translate.py --gc=hybrid targetpypystandalone.py --allworkingmodules --faassen
+    python translate.py --gc=hybrid --thread targetpypystandalone.py --allworkingmodules --faassen
+
+Dependencies: this will compile all supported built-in modules, some of
+which have external dependencies.  On a Debian Linux, for example, you
+need to install the following packages: a full C compiler like gcc;
+``python-dev, python-ctypes``; ``libffi-dev, libz-dev, libbz2-dev,
+libncurses-dev``.
 
 This whole process will take some time and quite a lot of memory (around
 1GB).  It creates an executable ``pypy-c`` in the current directory.
 The ``--gc=hybrid`` option means that the ``pypy-c`` will use our own
 exact generational garbage collector implementation, whose performance
-is rather good nowadays.  The ``--faassen`` option enables all the
+is rather good nowadays.  The ``--thread`` option enables the thread
+module, which is still slightly experimental.
+The ``--faassen`` option enables all the
 worthwhile performance optimizations, but slows down the translation
-itself.  On Linux 32-bit Intel machines you can also add
-``--gcrootfinder=asmgcc`` after ``--gc=hybrid`` for extra speed (and
-extra translation time).
+itself.  On Linux 32-bit Intel machines, if you don't need threads, you
+can get some extra speed (and extra translation time) by removing
+``--thread`` and replacing it with ``--gcrootfinder=asmgcc``.
 
-At the moment, threads only work with the `Boehm-Demers-Weiser garbage
-collector`_.  So to enable them, you need instead::
-
-    cd pypy/translator/goal
-    python translate.py --thread targetpypystandalone.py --allworkingmodules --faassen
-
+An alternative is to use the `Boehm-Demers-Weiser garbage
+collector`_ instead of our own.  For this, use ``--gc=boehm``.
 Be sure to install Boehm before starting the translation (e.g. by running
 ``apt-get install libgc-dev`` on Debian or Ubuntu).  Translating with Boehm
-is a bit faster and less memory-hungry than translating with our own GCs.
+is somewhat faster and less memory-hungry than translating with our own GCs.
 
 In any case, as described above, you can find the produced executable under the
 name ``pypy-c``.  Type ``pypy-c --help`` to see the options it supports --
    * ``--gc=boehm|ref|marknsweep|semispace|generation|hybrid``:
      choose between using
      the `Boehm-Demers-Weiser garbage collector`_, our reference
-     counting implementation or three of own collector implementations
+     counting implementation or four of own collector implementations
      (Boehm's collector is the default).
 
 Find a more detailed description of the various options in our `configuration

pypy/doc/index.txt

 ===================================
 
 PyPy can be used to run Python programs on Linux, OS/X,
-Windows, on top of .NET, and (recently) on top of Java.
+Windows, on top of .NET, and on top of Java.
 It is recommended to try out the current Subversion HEAD,
 which contains `major improvements`__ since the last release.
 
 
 PyPy is mainly developed on Linux and Mac OS X.  Windows is supported,
 but platform-specific bugs tend to take longer before we notice and fix
-them.  About 64-bit machines: although support is mostly present, we
-decided to stop tracking and fixing the remaining issues for a while, as
-an attempt to keep some focus.  So PyPy requires a 32-bit machine or OS
-for now.
+them.  Linux 64-bit machines are supported (though it may also take some
+time before we notice and fix bugs).
 
 PyPy's own tests, daily updated, `on Linux`_, `on Windows`_
  and `on built pypy-c`_.

pypy/doc/redirections

     'news.html': 'home.html',
     'contact.html': 'home.html',
     'jit.html': 'jit/index.html',
+    'standalone-howto.html': 'faq.html#pypy-translation-tool-chain',
 }
 

pypy/interpreter/astcompiler/misc.py

 
     return "_%s%s" % (klass, name)
 
+class Queue(object):
+    def __init__(self, item):
+        self.head = [item]
+        self.tail = []
+
+    def pop(self):
+        if self.head:
+            return self.head.pop()
+        else:
+            for i in range(len(self.tail)-1, -1, -1):
+                self.head.append(self.tail[i])
+            self.tail = []
+            return self.head.pop()
+
+    def extend(self, items):
+        self.tail.extend(items)
+
+    def nonempty(self):
+        return self.tail or self.head
+
 def set_filename(filename, tree):
     """Set the filename attribute to filename on every node in tree"""
-    worklist = [tree]
-    while worklist:
-        node = worklist.pop(0)
+    worklist = Queue(tree)
+    while worklist.nonempty():
+        node = worklist.pop()
         assert isinstance(node, ast.Node)
         node.filename = filename
         worklist.extend(node.getChildNodes())

pypy/interpreter/astcompiler/pycodegen.py

     def visitListComp(self, node):
         self.set_lineno(node)
         # setup list
-        tmpname = "$list%d" % self.__list_count
+        tmpname = "_[%d]" % self.__list_count
         self.__list_count = self.__list_count + 1
         self.emitop_int('BUILD_LIST', 0)
         self.emit('DUP_TOP')

pypy/interpreter/executioncontext.py

 def new_framestack():
     return Stack()
 
+def app_profile_call(space, w_callable, frame, event, w_arg):
+    space.call_function(w_callable,
+                        space.wrap(frame),
+                        space.wrap(event), w_arg)
+
 class ExecutionContext:
     """An ExecutionContext holds the state of an execution thread
     in the Python interpreter."""
         self.space = space
         self.framestack = new_framestack()
         self.w_tracefunc = None
-        self.w_profilefunc = None
         self.is_tracing = 0
         self.ticker = 0
         self.pending_actions = []
         self.compiler = space.createcompiler()
+        self.profilefunc = None
+        self.w_profilefuncarg = None
 
     def enter(self, frame):
         if self.framestack.depth() > self.space.sys.recursionlimit:
             self.framestack.push(frame)
 
     def leave(self, frame):
-        if self.w_profilefunc:
+        if self.profilefunc:
             self._trace(frame, 'leaveframe', None)
                 
         if not frame.hide():
         def __init__(self):
             self.framestack = new_framestack()
             self.w_tracefunc = None
-            self.w_profilefunc = None
+            self.profilefunc = None
+            self.w_profilefuncarg = None
             self.is_tracing = 0
 
         def enter(self, ec):
             ec.framestack = self.framestack
             ec.w_tracefunc = self.w_tracefunc
-            ec.w_profilefunc = self.w_profilefunc
+            ec.profilefunc = self.profilefunc
+            ec.w_profilefuncarg = self.w_profilefuncarg
             ec.is_tracing = self.is_tracing
 
         def leave(self, ec):
             self.framestack = ec.framestack
             self.w_tracefunc = ec.w_tracefunc
-            self.w_profilefunc = ec.w_profilefunc
+            self.profilefunc = ec.profilefunc
+            self.w_profilefuncarg = ec.w_profilefuncarg
             self.is_tracing = ec.is_tracing
 
         # the following interface is for pickling and unpickling
     def setprofile(self, w_func):
         """Set the global trace function."""
         if self.space.is_w(w_func, self.space.w_None):
-            self.w_profilefunc = None
+            self.profilefunc = None
+            self.w_profilefuncarg = None
         else:
-            self.w_profilefunc = w_func
+            self.w_profilefuncarg = w_func
+            self.profilefunc = app_profile_call
+
+    def setllprofile(self, func, w_arg):
+        self.profilefunc = func
+        if func is not None and w_arg is None:
+            raise ValueError("Cannot call setllprofile with real None")
+        self.w_profilefuncarg = w_arg
 
     def call_tracing(self, w_func, w_args):
         is_tracing = self.is_tracing
                 frame.locals2fast()
 
         # Profile cases
-        if self.w_profilefunc is not None:
+        if self.profilefunc is not None:
             if event not in ['leaveframe', 'call']:
                 return
 
             self.is_tracing += 1
             try:
                 try:
-                    w_result = space.call_function(self.w_profilefunc,
-                                                        space.wrap(frame),
-                                                        space.wrap(event), w_arg)
+                    self.profilefunc(space, self.w_profilefuncarg,
+                                     frame, event, w_arg)
                 except:
-                    self.w_profilefunc = None
+                    self.profilefunc = None
+                    self.w_profilefuncarg = None
                     raise
 
             finally:

pypy/interpreter/function.py

         return space.newtuple(values_w)
 
     def fset_func_defaults(space, self, w_defaults):
+        if space.is_w(w_defaults, space.w_None):
+            self.defs_w = []
+            return
         if not space.is_true( space.isinstance( w_defaults, space.w_tuple ) ):
-            raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object") )
+            raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object or None") )
         self.defs_w = space.unpackiterable( w_defaults )
 
     def fdel_func_defaults(space, self):

pypy/interpreter/gateway.py

 
     def visit__object(self, typ):
         name = int_unwrapping_space_method(typ)
-        self.run_args.append("space.%s_w(%s)" %
+        self.run_args.append("space.%s(%s)" %
                              (name, self.scopenext()))
 
     def visit_index(self, typ):
 
     def visit__object(self, typ):
         name = int_unwrapping_space_method(typ)
-        self.unwrap.append("space.%s_w(%s)" % (name,
+        self.unwrap.append("space.%s(%s)" % (name,
                                                self.nextarg()))
 
     def visit_index(self, typ):
     make_fastfunc = staticmethod(make_fastfunc)
 
 def int_unwrapping_space_method(typ):
-    assert typ in (int, str, float, unicode, r_longlong, r_uint, r_ulonglong)
+    assert typ in (int, str, float, unicode, r_longlong, r_uint, r_ulonglong, bool)
     if typ is r_int is r_longlong:
-        return 'r_longlong'
+        return 'r_longlong_w'
     elif typ is r_uint:
-        return 'uint'
+        return 'uint_w'
+    elif typ is bool:
+        return 'is_true'
     else:
-        return typ.__name__
+        return typ.__name__ + '_w'
 
 class BuiltinCode(eval.Code):
     "The code object implementing a built-in (interpreter-level) hook."

pypy/interpreter/miscutils.py

     def getmainthreadvalue(self):
         return self._value
 
-    def getGIL(self):
-        return None    # XXX temporary hack!
-
 
 class Action(object):
     """Abstract base class for actions that must be performed regularly,

pypy/interpreter/pycode.py

             #hidden_applevel=False, magic = 62061 | 0x0a0d0000
         ]
         return space.newtuple([new_inst, space.newtuple(tup)])
+
+    def repr(self, space):
+        return space.wrap("<code object %s, file '%s', line %d>" % (
+            self.co_name, self.co_filename, self.co_firstlineno))
+    repr.unwrap_spec = ['self', ObjSpace]

pypy/interpreter/test/test_code.py

 
+from pypy.conftest import gettestobjspace
+from pypy.interpreter import gateway
+import py
 
 class AppTestCodeIntrospection:
+    def setup_class(cls):
+        space = gettestobjspace()
+        cls.space = space
+        if py.test.config.option.runappdirect:
+            cls.w_file = space.wrap(__file__[:-1])
+        else:
+            cls.w_file = space.wrap("None<%s" % gateway.__file__[:-1])
 
     def test_attributes(self):
         def f(): pass
 
     def test_inspect(self):
         if not hasattr(len, 'func_code'):
-            skip("CPython: no func_code attribute on built-in functions")
+            skip("Cannot run this test if builtins have no func_code")
         import inspect
         args, varargs, varkw = inspect.getargs(len.func_code)
         assert args == ['obj']
         assert varargs is None
         assert varkw is None
+
+    def test_repr(self):
+        def f():
+            xxx
+        res = repr(f.func_code)
+        expected = ["<code object f",
+                    self.file,
+                    'line']
+        for i in expected:
+            assert i in res
+

pypy/interpreter/test/test_executioncontext.py

         assert a1.counter == 1
         assert a2.counter == 10
         assert a3.counter == 1
+
+    def test_llprofile(self):
+        l = []
+        
+        def profile_func(space, w_arg, event, frame, w_aarg):
+            assert w_arg is space.w_None
+            l.append(frame)
+        
+        space = self.space
+        space.getexecutioncontext().setllprofile(profile_func, space.w_None)
+        space.appexec([], """():
+        pass
+        """)
+        space.getexecutioncontext().setllprofile(None, None)
+        assert l == ['call', 'return', 'call', 'return']
+

pypy/interpreter/test/test_function.py

         def f(): pass
         assert hasattr(f, 'func_code')
         assert f.func_defaults == None
+        f.func_defaults = None
+        assert f.func_defaults == None
         assert f.func_dict == {}
         assert type(f.func_globals) == dict
         #self.assertEquals(f.func_closure, None)  XXX

pypy/interpreter/test/test_gateway.py

             space.call_function(w_app_g3, w('foo'), w('bar')),
             w('foobar'))
 
+    def test_interp2app_unwrap_spec_bool(self):
+        space = self.space
+        w = space.wrap
+        def g(space, b):
+            return space.wrap(b)
+        app_g = gateway.interp2app(g, unwrap_spec=[gateway.ObjSpace, bool])
+        w_app_g = space.wrap(app_g)
+        assert self.space.eq_w(space.call_function(w_app_g, space.wrap(True)),
+                               space.wrap(True))
+
     def test_interp2app_unwrap_spec_args_w(self):
         space = self.space
         w = space.wrap

pypy/interpreter/typedef.py

     __hash__ = interp2app(PyCode.descr_code__hash__),
     __reduce__   = interp2app(PyCode.descr__reduce__,
                               unwrap_spec=['self', ObjSpace]),
+    __repr__ = interp2app(PyCode.repr),
     co_argcount = interp_attrproperty('co_argcount', cls=PyCode),
     co_nlocals = interp_attrproperty('co_nlocals', cls=PyCode),
     co_stacksize = interp_attrproperty('co_stacksize', cls=PyCode),

pypy/lang/gameboy/cartridge.py

 
 from pypy.lang.gameboy.ram import iMemory
 
+import math
+
 #from pypy.rlib.rstr import str_replace
 
 import os
 
+# HELPERS ----------------------------------------------------------------------
+
 def has_cartridge_battery(self, cartridge_type):    
-    return (cartridge_type == constants.TYPE_MBC1_RAM_BATTERY \
-                or cartridge_type == constants.TYPE_MBC2_BATTERY \
-                or cartridge_type == constants.TYPE_MBC3_RTC_BATTERY \
-                or cartridge_type == constants.TYPE_MBC3_RTC_RAM_BATTERY \
-                or cartridge_type == constants.TYPE_MBC3_RAM_BATTERY \
-                or cartridge_type == constants.TYPE_MBC5_RAM_BATTERY \
-                or cartridge_type == constants.TYPE_MBC5_RUMBLE_RAM_BATTERY \
+    return (cartridge_type == constants.TYPE_MBC1_RAM_BATTERY 
+                or cartridge_type == constants.TYPE_MBC2_BATTERY 
+                or cartridge_type == constants.TYPE_MBC3_RTC_BATTERY 
+                or cartridge_type == constants.TYPE_MBC3_RTC_RAM_BATTERY 
+                or cartridge_type == constants.TYPE_MBC3_RAM_BATTERY 
+                or cartridge_type == constants.TYPE_MBC5_RAM_BATTERY 
+                or cartridge_type == constants.TYPE_MBC5_RUMBLE_RAM_BATTERY 
                 or cartridge_type == constants.TYPE_HUC1_RAM_BATTERY)
 
 
         else:
             raise InvalidMemoryBankTypeError("Unsupported memory bank controller (0x"+hex(cartridge_type)+")")
 
-class InvalidMemoryBankTypeError(Exception):
-    pass
-
 def map_to_byte( string):
     mapped = [0]*len(string)
     for i in range(len(string)):
-        mapped[i]  = ord(string[i]) & 0xFF
+        mapped[i]  = ord(string[i])
     return mapped
 
 def map_to_string(int_array):
     for i in range(len(int_array)):
         mapped[i]  = chr(int_array[i])
     return ("").join(mapped)
+
+# EXCEPIONS --------------------------------------------------------------------
+
+class InvalidMemoryBankTypeError(Exception):
+    pass
+
+class InvalidMemoryAccessException(Exception):
+    pass
+
+class InvalidSizeException(Exception):
+    pass
+
+class CartridgeHeaderCorruptedException(Exception):
+    pass
+
+class CartridgeTruncatedException(Exception):
+    pass
+
         
 # ==============================================================================
 # CARTRIDGE
     
     def __init__(self, clock):
         assert isinstance(clock, Clock)
-        self.clock = clock
+        self.clock     = clock
         self.cartridge = None
-        self.mbc = None
+        self.mbc       = None
         
     def reset(self):
         if not self.has_battery():
-            self.ram[0:len(self.ram):1] = 0xFF
+            self.ram = [0xFF]*len(self.ram)
         self.mbc.reset()
 
     def read(self, address):
     def load(self, cartridge, verify=True):
         assert isinstance(cartridge, CartridgeFile)
         self.cartridge = cartridge
-        self.rom  = self.cartridge.read()
+        self.rom       = self.cartridge.read()
         if verify:
             self.check_rom()
         self.create_ram()
         self.load_battery()
-        self.mbc = self.create_bank_controller(self.get_memory_bank_type(), \
+        self.mbc = self.create_bank_controller(self.get_memory_bank_type(), 
                                                self.rom, self.ram, self.clock)
+        print self
         
     def check_rom(self):
         if not self.verify_header():
-            raise Exception("Cartridge header is corrupted")
+            raise CartridgeHeaderCorruptedException("Cartridge Header is corrupted")
         if self.cartridge.get_size() < self.get_rom_size():
-            raise Exception("Cartridge is truncated")
+            raise CartridgeTruncatedException("Cartridge is truncated")
         
     def create_ram(self):
         ram_size = self.get_ram_size()
             self.cartridge.write_battery(self.ram)
             
     def get_memory_bank_type(self):
-        return self.rom[constants.CARTRIDGE_TYPE_ADDRESS] & 0xFF
+        return self.rom[constants.CARTRIDGE_TYPE_ADDRESS]
     
     def get_memory_bank(self):
         return self.mbc
         return self.rom
         
     def get_rom_size(self):
-        rom_size = self.rom[constants.CARTRIDGE_ROM_SIZE_ADDRESS] & 0xFF
+        rom_size = self.rom[constants.CARTRIDGE_ROM_SIZE_ADDRESS]
         if rom_size>=0x00 and rom_size<=0x07:
             return 32768 << rom_size
         return -1
         
     def get_ram_size(self):
-        return constants.CARTRIDGE_RAM_SIZE_MAPPING[self.rom[constants.CARTRIDGE_RAM_SIZE_ADDRESS]]
+        return constants.CARTRIDGE_RAM_SIZE_MAPPING[
+                self.rom[constants.CARTRIDGE_RAM_SIZE_ADDRESS]]
     
     def get_destination_code(self):
-        return self.rom[constants.DESTINATION_CODE_ADDRESS] & 0xFF
+        return self.rom[constants.DESTINATION_CODE_ADDRESS]
     
     def get_licensee_code():
-        return self.rom[constants.LICENSEE_ADDRESS] & 0xFF
+        return self.rom[constants.LICENSEE_ADDRESS]
 
     def get_rom_version(self):
-        return self.rom[constants.CARTRIDGE_ROM_VERSION_ADDRESS] & 0xFF
+        return self.rom[constants.CARTRIDGE_ROM_VERSION_ADDRESS]
     
     def get_header_checksum(self):
-        return self.rom[constants.HEADER_CHECKSUM_ADDRESS] & 0xFF
+        return self.rom[constants.HEADER_CHECKSUM_ADDRESS]
     
     def get_checksum(self):
-        return ((self.rom[constants.CHECKSUM_A_ADDRESS] & 0xFF) << 8) \
-                + (self.rom[constants.CHECKSUM_B_ADDRESS] & 0xFF)
-    
+        return ((self.rom[constants.CHECKSUM_A_ADDRESS]) << 8) \
+                + (self.rom[constants.CHECKSUM_B_ADDRESS])
+
     def has_battery(self):
         return has_cartridge_battery(self.get_memory_bank_type())
     
         checksum = 0
         for address in range(len(self.rom)):
             if address is not 0x014E and address is not 0x014F:
-                checksum = (checksum + (self.rom[address] & 0xFF)) & 0xFFFF
+                checksum = (checksum + (self.rom[address])) & 0xFF
         return (checksum == self.get_checksum())
     
     def verify_header(self):
             return False
         checksum = 0xE7
         for address in range(0x0134, 0x014C):
-            checksum = (checksum - (self.rom[address] & 0xFF)) & 0xFF
+            checksum = (checksum - (self.rom[address])) & 0xFF
         return (checksum == self.get_header_checksum())
     
     def create_bank_controller(self, type, rom, ram, clock_driver):
         return MEMORY_BANK_MAPPING[type](rom, ram, clock_driver)
 
+    
+    def __repr__(self):
+        return "Type=%s, Destination: %s ramSize: %sKB romSize: %sKB" % \
+                        (self.get_memory_bank_type(), self.get_destination_code(),
+                        self.get_ram_size(), self.get_rom_size()/1024)
+        
 
 # ------------------------------------------------------------------------------
 
             self.load(file)
         
     def reset(self):
-        self.cartridge_name = ""
-        self.cartridge_file_path = ""
-        self.cartridge_stream = None
+        self.cartridge_name          = ""
+        self.cartridge_file_path     = ""
+        self.cartridge_stream        = None
         self.cartridge_file_contents = None
-        self.battery_name = ""
-        self.battery_file_path = ""
-        self.battery_stream = None
-        self.battery_file_contents = None
+        self.battery_name            = ""
+        self.battery_file_path       = ""
+        self.battery_stream          = None
+        self.battery_file_contents   = None
         
         
     def load(self, cartridge_path):
-        if cartridge_path is None:
-            raise Exception("cartridge_path cannot be None!")
-        cartridge_path = str(cartridge_path)
-        self.cartridge_file_path = cartridge_path
-        self.cartridge_stream = open_file_as_stream(cartridge_path)
-        self.cartridge_file_contents = map_to_byte( \
+        cartridge_path               = str(cartridge_path)
+        self.cartridge_file_path     = cartridge_path
+        self.cartridge_stream        = open_file_as_stream(cartridge_path)
+        self.cartridge_file_contents = map_to_byte(
                                                 self.cartridge_stream.readall())
         self.load_battery(cartridge_path)
         
     def load_battery(self, cartridge_file_path):
         self.battery_file_path = self.create_battery_file_path(cartridge_file_path)
         if self.has_battery():
-            self.battery_stream = open_file_as_stream(self.battery_file_path)
-            self.battery_file_contents = map_to_byte( \
-                                             self.battery_stream.readall())
+            self.read_battery()
+    
+    def read_battery(self):
+        self.battery_stream = open_file_as_stream(self.battery_file_path)
+        self.battery_file_contents = map_to_byte(self.battery_stream.readall())
     
     def create_battery_file_path(self, cartridge_file_path):
         if cartridge_file_path.endswith(constants.CARTRIDGE_FILE_EXTENSION):
         return self.cartridge_file_contents
     
     def read_battery(self):
-        return  self.battery_file_contents
+        return self.battery_file_contents
     
     def write_battery(self, ram):
         output_stream = open_file_as_stream(self.battery_file_path, "w")
     
     def __init__(self, rom, ram, clock_driver,
                     min_rom_bank_size=0, max_rom_bank_size=0,
-                    min_ram_bank_size=0, max_ram_bank_size=0):
+                    min_ram_bank_size=0, max_ram_bank_size=0, 
+                    rom_bank_size=constants.ROM_BANK_SIZE):
         self.clock             = clock_driver
         self.min_rom_bank_size = min_rom_bank_size
         self.max_rom_bank_size = max_rom_bank_size
         self.min_ram_bank_size = min_ram_bank_size
         self.max_ram_bank_size = max_ram_bank_size
+        self.rom_bank_size     = rom_bank_size
+        self.rom_bank          = self.rom_bank_size
         self.reset()
         self.set_rom(rom)
         self.set_ram(ram)
 
     def reset(self):
-        self.rom_bank   = constants.ROM_BANK_SIZE
         self.ram_bank   = 0
         self.ram_enable = False
         self.rom        = []
         self.ram_size   = 0
     
     def set_rom(self, buffer):
-        banks = int(len(buffer) / constants.ROM_BANK_SIZE)
+        banks = int(len(buffer) / self.rom_bank_size)
         if banks < self.min_rom_bank_size or banks > self.max_rom_bank_size:
-            raise Exception("Invalid ROM size %s, should be in [%s %s]" % \
-                            (hex(banks), hex(self.min_rom_bank_size), \
+            raise InvalidSizeException("Invalid ROM size %s, should be in [%s %s]" % 
+                            (hex(banks), hex(self.min_rom_bank_size), 
                              hex(self.max_rom_bank_size)))
-        self.rom = buffer
-        self.rom_size = constants.ROM_BANK_SIZE * banks - 1
+        self.rom      = buffer
+        self.rom_size = self.rom_bank_size * banks - 1
 
 
     def set_ram(self, buffer):
         banks = int(len(buffer) / constants.RAM_BANK_SIZE)
         if banks < self.min_ram_bank_size or banks > self.max_ram_bank_size:
-            raise Exception("Invalid RAM size %s, should be in [%s %s]" % \
-                            (hex(banks), hex(self.min_ram_bank_size), \
+            raise InvalidSizeException("Invalid RAM size %s, should be in [%s %s]" % 
+                            (hex(banks), hex(self.min_ram_bank_size), 
                              hex(self.max_ram_bank_size)))
-        self.ram = buffer
+        self.ram      = buffer
         self.ram_size = constants.RAM_BANK_SIZE * banks - 1
         
         
-    def read(self, address):    
-        if address <= 0x3FFF: # 0000-3FFF
-            return self.rom[address] & 0xFF
-        elif address <= 0x7FFF:# 4000-7FFF
-            return self.rom[self.rom_bank + (address & 0x3FFF)] & 0xFF
-        elif address >= 0xA000 and address <= 0xBFFF: # A000-BFFF
+    def read(self, address):
+        # 0000-3FFF  
+        if address <= 0x3FFF:
+            return self.rom[address]
+        # 4000-7FFF
+        elif address <= 0x7FFF:
+            return self.rom[self.rom_bank + (address & 0x3FFF)]
+        # A000-BFFF
+        elif address >= 0xA000 and address <= 0xBFFF:
             if self.ram_enable:
-                return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF
+                return self.ram[self.ram_bank + (address & 0x1FFF)]
             else:
+                #return 0xFF
                 raise Exception("RAM is not Enabled")
-        raise Exception("MBC: Invalid address, out of range: %s" % hex(address))
+        #return 0xFF
+        raise InvalidMemoryAccessException("MBC: Invalid address, out of range: %s" 
+                                           % hex(address))
     
     def write(self, address, data):
-        raise Exception("MBC: Invalid write access")
+        raise InvalidMemoryAccessException("MBC: Invalid write access")
     
     def write_ram_enable(self, address, data):
         if self.ram_size > 0:
                         max_ram_bank_size=0xFFFFFF)
         
     def write(self, address, data):
-        self.ram[address] = data
+        self.ram[self.ram_bank + (address & 0x1FFF)] = data
     
 
 #-------------------------------------------------------------------------------
 
 class MBC1(MBC):
     """
-    PyBoy GameBoy (TM) Emulator
+    PyGirl GameBoy (TM) Emulator
     
-    Memory Bank Controller 1 (2MB constants.ROM, 32KB constants.RAM)
+    Memory Bank Controller 1 (2MB ROM, 32KB RAM)
      
     0000-3FFF    ROM Bank 0 (16KB)
     4000-7FFF    ROM Bank 1-127 (16KB)
         self.memory_model = 0
 
     def write(self, address, data):
-        if address <= 0x1FFF:  # 0000-1FFF
+        # 0000-1FFF
+        if address <= 0x1FFF:
             self.write_ram_enable(address, data)
-        elif address <= 0x3FFF: # 2000-3FFF
+        # 2000-3FFF
+        elif address <= 0x3FFF:
             self.write_rom_bank_1(address, data)
-        elif address <= 0x5FFF: # 4000-5FFF
+        # 4000-5FFF
+        elif address <= 0x5FFF:
             self.write_rom_bank_2(address, data)
-        elif address <= 0x7FFF: # 6000-7FFF
+        # 6000-7FFF
+        elif address <= 0x7FFF:
             self.memory_model = data & 0x01
-        elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: # A000-BFFF
+        # A000-BFFF
+        elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable:
             self.ram[self.ram_bank + (address & 0x1FFF)] = data
         else:
-            raise Exception("Invalid memory Access address: %s" % hex(address))
+            return 
+            #raise InvalidMemoryAccessException("MBC 1Invalid memory Access address: %s" 
+            #                                   % hex(address))
 
     def write_rom_bank_1(self, address, data):
         if (data & 0x1F) == 0:
             data = 1
         if self.memory_model == 0:
-            self.rom_bank = ((self.rom_bank & 0x180000) + ((data & 0x1F) << 14)) & self.rom_size
+            self.rom_bank = ((self.rom_bank & 0x180000) + 
+                             ((data & 0x1F) << 14)) & self.rom_size
         else:
             self.rom_bank = ((data & 0x1F) << 14) & self.rom_size
         
     def write_rom_bank_2(self, address, data):
         if self.memory_model == 0:
-            self.rom_bank = ((self.rom_bank & 0x07FFFF) + ((data & 0x03) << 19)) & self.rom_size
+            self.rom_bank = ((self.rom_bank & 0x07FFFF) + 
+                             ((data & 0x03) << 19)) & self.rom_size
         else:
             self.ram_bank = ((data & 0x03) << 13) & self.ram_size
   
       
 class MBC2(MBC):
     """
-    PyBoy GameBoy (TM) Emulator
+    PyGirl GameBoy (TM) Emulator
     
-    Memory Bank Controller 2 (256KB constants.ROM, 512x4bit constants.RAM)
+    Memory Bank Controller 2 (256KB ROM, 512x4bit RAM)
     
     0000-3FFF    ROM Bank 0 (16KB)
     4000-7FFF    ROM Bank 1-15 (16KB)
     A000-A1FF    RAM Bank (512x4bit)
      """
      
-    RAM_BANK_SIZE = 512
-
     def __init__(self, rom, ram, clock_driver):
         MBC.__init__(self, rom, ram, clock_driver,
-                    min_ram_bank_size=1,
-                    max_ram_bank_size=1,
-                    min_rom_bank_size=2,   
-                    max_rom_bank_size=16)
+                    min_ram_bank_size=1, max_ram_bank_size=1,
+                    min_rom_bank_size=2, max_rom_bank_size=16,
+                    rom_bank_size=512)
         
-    
     def read(self, address):
         if address > 0xA1FF:
-            raise Exception("MBC2 out of Bounds: %s" % hex(address))
+            raise InvalidMemoryAccessException("MBC2 out of Bounds: %s" 
+                                               % hex(address))
         elif address >= 0xA000:
             return self.ram[address & 0x01FF]
-        elif address >= 0xA000 and address <= 0xA1FF: # A000-BFFF
+        # A000-BFFF
+        elif address >= 0xA000 and address <= 0xA1FF:
             if self.ram_enable:
-                return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF
+                return self.ram[self.ram_bank + (address & 0x1FFF)]
             else:
                 raise Exception("RAM is not Enabled")
         else:
             return MBC.read(self, address)
         
     def write(self, address, data):
-        if address <= 0x1FFF:  # 0000-1FFF
+        # 0000-1FFF
+        if address <= 0x1FFF:
             self.write_ram_enable(address, data)
-        elif address <= 0x3FFF: # 2000-3FFF
+        # 2000-3FFF
+        elif address <= 0x3FFF:
             self.write_rom_bank(address, data)
-        elif address >= 0xA000 and address <= 0xA1FF: # A000-A1FF
+        # A000-A1FF
+        elif address >= 0xA000 and address <= 0xA1FF:
             self.write_ram(address, data)
             
     def write_rom_bank(self, address, data):
 
 class MBC3(MBC):
     """
-    PyBoy GameBoy (TM) Emulator
+    PyGirl GameBoy (TM) Emulator
     
-    Memory Bank Controller 3 (2MB constants.ROM, 32KB constants.RAM, Real Time Clock)
+    Memory Bank Controller 3 (2MB ROM, 32KB RAM, Real Time Clock)
     
     0000-3FFF    ROM Bank 0 (16KB)
     4000-7FFF    ROM Bank 1-127 (16KB)
     A000-BFFF    RAM Bank 0-3 (8KB)
     """
+    
     def __init__(self, rom, ram, clock_driver):
         MBC.__init__(self, rom, ram, clock_driver,
                         min_ram_bank_size=0,
                         min_rom_bank_size=2,  
                         max_rom_bank_size=128)
 
-
     def reset(self):
         MBC.reset(self)
         self.clock_latched_daysclock_latched_control = None
         self.clock_latched_days     = 0
         self.clock_latched_control  = 0
 
-
     def read(self, address):
-        if address >= 0xA000 and address <= 0xBFFF:  # A000-BFFF
+        # A000-BFFF
+        if address >= 0xA000 and address <= 0xBFFF:
             if self.ram_bank >= 0:
-                return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF
+                return self.ram[self.ram_bank + (address & 0x1FFF)]
             else:
                 return self.read_clock_data(address)
         else:
             return self.clock_latched_days
         if self.clock_register == 0x0C:
             return self.clock_latched_control
-        raise Exception("MBC*.read_clock_data invalid address %i")
+        raise InvalidMemoryAccessException("MBC3.read_clock_data invalid address %i")
     
     def write(self, address, data):
-        if address <= 0x1FFF: # 0000-1FFF
+        print hex(address), hex(data)
+        # 0000-1FFF
+        if address <= 0x1FFF:
             self.write_ram_enable(address, data)
-        elif address <= 0x3FFF: # 2000-3FFF
+        # 2000-3FFF
+        elif address <= 0x3FFF:
             self.write_rom_bank(address, data)
-        elif address <= 0x5FFF:  # 4000-5FFF
+        # 4000-5FFF
+        elif address <= 0x5FFF:
             self.write_ram_bank(address, data)
-        elif address <= 0x7FFF: # 6000-7FFF
+        # 6000-7FFF
+        elif address <= 0x7FFF:
             self.write_clock_latch(address, data)
-        elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: # A000-BFFF
+        # A000-BFFF
+        elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable:
             if self.ram_bank >= 0:
                 self.ram[self.ram_bank + (address & 0x1FFF)] = data
             else:
         self.clock_latched_minutes = self.clock_minutes
         self.clock_latched_hours   = self.clock_hours
         self.clock_latched_days    = self.clock_days & 0xFF
-        self.clock_latched_control = (self.clock_control & 0xFE) | ((self.clock_days >> 8) & 0x01)
+        self.clock_latched_control = (self.clock_control & 0xFE) | \
+                                     ((self.clock_days >> 8) & 0x01)
 
     def update_clock(self):
         now = self.clock.get_time()
-        if (self.clock_control & 0x40) == 0:
-            elapsed = now - self.clock_time
-            while elapsed >= 246060:
-                elapsed -= 246060
-                self.clock_days+=1
-            while elapsed >= 6060:
-                elapsed -= 6060
-                self.clock_hours+=1
-            while elapsed >= 60:
-                elapsed -= 60
-                self.clock_minutes+=1
-            self.clock_seconds += elapsed
-            while self.clock_seconds >= 60:
-                self.clock_seconds -= 60
-                self.clock_minutes+=1
-            while self.clock_minutes >= 60:
-                self.clock_minutes -= 60
-                self.clock_hours+=1
-            while self.clock_hours >= 24:
-                self.clock_hours -= 24
-                self.clock_days+=1
-            while self.clock_days >= 512:
-                self.clock_days -= 512
-                self.clock_control |= 0x80
+        elapsed = now - self.clock_time
         self.clock_time = now
+        if (self.clock_control & 0x40) != 0:
+            return
+        elapsed += self.clock_days * 24*60*60
+        elapsed += self.clock_hours * 60*60
+        elapsed += self.clock_minutes * 60
+        elapsed += self.clock_seconds
+        
+        days = int(math.floor(elapsed / (24.0*60*60.0)))
+        self.clock_days += days
+        elapsed -= days * 24*60*60
+
+        hours = int(math.floor(elapsed / (60*60)))
+        self.clock_hours += hours
+        elapsed -= hours * 60*60
+        
+        minutes = int(math.floor(elapsed / 60))
+        self.clock_minutes += minutes
+        elapsed -= minutes * 60
+        
+        self.clock_seconds += elapsed
+        
+        if self.clock_days >= 512:
+            self.clock_days %= 512
+            self.clock_control |= 0x80
 
 
 #-------------------------------------------------------------------------------
 
 class MBC5(MBC):
     """
-    PyBoy GameBoy (TM) Emulator
+    PyGirl GameBoy (TM) Emulator
     
-    Memory Bank Controller 5 (8MB constants.ROM, 128KB constants.RAM)
+    Memory Bank Controller 5 (8MB ROM, 128KB RAM)
      *
     0000-3FFF    ROM Bank 0 (16KB)
     4000-7FFF    ROM Bank 1-511 (16KB)
         
     def write(self, address, data):
         address = int(address)
-        if address <= 0x1FFF:  # 0000-1FFF
+        # 0000-1FFF
+        if address <= 0x1FFF:  
             self.write_ram_enable(address, data)
-        elif address <= 0x2FFF:  # 2000-2FFF
-            self.rom_bank = ((self.rom_bank & (0x01 << 22)) + \
-                             ((data & 0xFF) << 14)) & self.rom_size
-        elif address <= 0x3FFF: # 3000-3FFF
-            self.rom_bank = ((self.rom_bank & (0xFF << 14)) + \
+        # 2000-2FFF
+        elif address <= 0x2FFF:
+            self.rom_bank = ((self.rom_bank & (0x01 << 22)) + 
+                             ((data) << 14)) & self.rom_size
+        # 3000-3FFF
+        elif address <= 0x3FFF:
+            self.rom_bank = ((self.rom_bank & (0xFF << 14)) + 
                              ((data & 0x01) << 22)) & self.rom_size
-        elif address <= 0x4FFF:  # 4000-4FFF
+        # 4000-4FFF
+        elif address <= 0x4FFF:
             self.write_ram_bank(address, data)
-        elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable:  # A000-BFFF
+        # A000-BFFF
+        elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable:
             self.ram[self.ram_bank + (address & 0x1FFF)] = data
 
     def write_ram_bank(self, address, data):
 
 class HuC3(MBC):
     """
-    PyBoy GameBoy (TM) Emulator
+    PyGirl GameBoy (TM) Emulator
     
-    Hudson Memory Bank Controller 3 (2MB constants.ROM, 128KB constants.RAM, constants.RTC)
+    Hudson Memory Bank Controller 3 (2MB ROM, 128KB RAM, RTC)
     
     0000-3FFF    ROM Bank 0 (16KB)
     4000-7FFF    ROM Bank 1-127 (16KB)
                         min_rom_bank_size=2,    
                         max_rom_bank_size=128)
 
-
     def reset(self):
         MBC.reset(self)
         self.ram_flag       = 0
         self.clock_shift    = 0
         self.clock_time     = self.clock.get_time()
 
-
     def read(self, address):
-        address = int(address)
-        if address >= 0xA000 and address <= 0xBFFF:# A000-BFFF
-            if self.ram_flag == 0x0C:
-                return self.ram_value
-            elif self.ram_flag == 0x0D:
-                return 0x01
-            elif self.ram_flag == 0x0A or self.ram_flag == 0x00:
-                if self.ram_size > 0:
-                    return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF
-            raise Exception("Huc3 read error")
+        # A000-BFFF
+        if address >= 0xA000 and address <= 0xBFFF:
+            return self.read_ram_or_flag(address)
         else:
             return MBC.read(self, address)
+        
+    def read_ram_or_flag(self, address):
+        if self.ram_flag == 0x0C:
+            return self.ram_value
+        elif self.ram_flag == 0x0D:
+            return 0x01
+        elif self.ram_flag == 0x0A or self.ram_flag == 0x00 and \
+                self.ram_size > 0:
+            return self.ram[self.ram_bank + (address & 0x1FFF)]
+        raise InvalidMemoryAccessException("Huc3 read error")
     
     def write(self, address, data):
-        address = int(address)
-        if address <= 0x1FFF: # 0000-1FFF
+        # 0000-1FFF
+        if address <= 0x1FFF:
             self.ram_flag = data
-        elif address <= 0x3FFF:# 2000-3FFF
+        # 2000-3FFF
+        elif address <= 0x3FFF:
             self.write_rom_bank(address, data)
-        elif address <= 0x5FFF: # 4000-5FFF
+        # 4000-5FFF
+        elif address <= 0x5FFF:
             self.ram_bank = ((data & 0x0F) << 13) & self.ram_size
-        elif address >= 0xA000 and address <= 0xBFFF: # A000-BFFF
+        # A000-BFFF
+        elif address >= 0xA000 and address <= 0xBFFF:
             self.write_ram_flag(address, data)
          
     def write_rom_bank(self, address, data):
             self.ram[self.ram_bank + (address & 0x1FFF)] = data
                         
     def write_with_ram_flag_0x0B(self, address, data):
-        if (data & 0xF0) == 0x10:
+        compare = data & 0xF0
+        if self.clock_shift > 24 and data != 0x60:
+            return
+        if compare == 0x10:
             self.write_ram_value_clock_shift(address, data)
-        elif (data & 0xF0) == 0x30:
+        elif compare == 0x30:
             self.write_clock_register_clock_shift(address, data)
-        elif (data & 0xF0) == 0x40:
+        elif compare == 0x40:
             self.write_clock_shift(address, data)
-        elif (data & 0xF0) == 0x50:
+        elif compare == 0x50:
             pass
-        elif (data & 0xF0) == 0x60:
+        elif compare == 0x60:
             self.ram_value = 0x01
          
     def write_ram_value_clock_shift(self, address, data):
-        if self.clock_shift > 24:
-            return
         self.ram_value = (self.clock_register >> self.clock_shift) & 0x0F
         self.clock_shift += 4
             
     def write_clock_register_clock_shift(self, address, data):
-        if self.clock_shift > 24:
-            return
         self.clock_register &= ~(0x0F << self.clock_shift)
         self.clock_register |= ((data & 0x0F) << self.clock_shift)
         self.clock_shift += 4
         now = self.clock.get_time()
         elapsed = now - self.clock_time
         # years (4 bits)
-        while elapsed >= 365246060:
-            self.clock_register += 1 << 24
-            elapsed -= 365246060
+        years = int(math.floor(elapsed / (365*24*60*60)))
+        elapsed -= years*365*24*60*60
         # days (12 bits)
-        while elapsed >= 246060:
-            self.clock_register += 1 << 12
-            elapsed -= 246060
+        days = int(math.floor(elapsed / (24*60*60)))
+        elapsed -= days*24*60*60
         # minutes (12 bits)
-        while elapsed >= 60:
-            self.clock_register += 1
-            elapsed -= 60
-        if (self.clock_register & 0x0000FFF) >= 2460:
-            self.clock_register += (1 << 12) - 2460
-        if (self.clock_register & 0x0FFF000) >= (365 << 12):
-            self.clock_register += (1 << 24) - (365 << 12)
+        minutes = int(math.floor(elapsed / 60))
+        elapsed -= minutes*60
+        
+        self.clock_register |= years << 24
+        self.clock_register |= days << 12
+        self.clock_register |= minutes
+        
         self.clock_time = now - elapsed
 
 

pypy/lang/gameboy/constants.py

 
 GAMEBOY_SCREEN_WIDTH  = 160
 GAMEBOY_SCREEN_HEIGHT = 144
+
 #___________________________________________________________________________
 # CATRIGE TYPES
 # ___________________________________________________________________________
 
+TYPE_ROM_ONLY                = 0x00
 
-TYPE_ROM_ONLY = 0x00
+TYPE_MBC1                    = 0x01
+TYPE_MBC1_RAM                = 0x02
+TYPE_MBC1_RAM_BATTERY        = 0x03
 
-TYPE_MBC1             = 0x01
-TYPE_MBC1_RAM         = 0x02
-TYPE_MBC1_RAM_BATTERY = 0x03
+TYPE_MBC2                    = 0x05
+TYPE_MBC2_BATTERY            = 0x06
 
-TYPE_MBC2         = 0x05
-TYPE_MBC2_BATTERY = 0x06
+TYPE_MBC3_RTC_BATTERY        = 0x0F
+TYPE_MBC3_RTC_RAM_BATTERY    = 0x10
+TYPE_MBC3                    = 0x11
+TYPE_MBC3_RAM                = 0x12
+TYPE_MBC3_RAM_BATTERY        = 0x13
 
-TYPE_MBC3_RTC_BATTERY     = 0x0F
-TYPE_MBC3_RTC_RAM_BATTERY = 0x10
-TYPE_MBC3                 = 0x11
-TYPE_MBC3_RAM             = 0x12
-TYPE_MBC3_RAM_BATTERY     = 0x13
-
-TYPE_MBC5             = 0x19
-TYPE_MBC5_RAM         = 0x1A
-TYPE_MBC5_RAM_BATTERY = 0x1B
+TYPE_MBC5                    = 0x19
+TYPE_MBC5_RAM                = 0x1A
+TYPE_MBC5_RAM_BATTERY        = 0x1B
 
 TYPE_MBC5_RUMBLE             = 0x1C
-TYPE_MBC5_RUMBLE_RAM          = 0x1D
+TYPE_MBC5_RUMBLE_RAM         = 0x1D
 TYPE_MBC5_RUMBLE_RAM_BATTERY = 0x1E
 
-TYPE_HUC3_RTC_RAM     = 0xFE
-TYPE_HUC1_RAM_BATTERY = 0xFF
+TYPE_HUC3_RTC_RAM            = 0xFE
+TYPE_HUC1_RAM_BATTERY        = 0xFF
 
-CARTRIDGE_TYPE_ADDRESS     = 0x0147
-CARTRIDGE_ROM_SIZE_ADDRESS = 0x0148
-CARTRIDGE_RAM_SIZE_ADDRESS = 0x0149
-CARTRIDGE_RAM_SIZE_MAPPING = {0x00:0, 0x01:8192, 0x02:8192, 0x03:32768}
-DESTINATION_CODE_ADDRESS   = 0x014A
-LICENSEE_ADDRESS           = 0x014B
-ROM_VERSION_ADDRESS        = 0x014C
-HEADER_CHECKSUM_ADDRESS    = 0x014D
-CHECKSUM_A_ADDRESS         = 0x014E
-CHECKSUM_B_ADDRESS         = 0x014F
+CARTRIDGE_TYPE_ADDRESS       = 0x0147
+CARTRIDGE_ROM_SIZE_ADDRESS   = 0x0148
+CARTRIDGE_RAM_SIZE_ADDRESS   = 0x0149
+CARTRIDGE_RAM_SIZE_MAPPING   = {0x00:0, 0x01:8192, 0x02:8192, 0x03:32768}
+DESTINATION_CODE_ADDRESS     = 0x014A
+LICENSEE_ADDRESS             = 0x014B
+ROM_VERSION_ADDRESS          = 0x014C
+HEADER_CHECKSUM_ADDRESS      = 0x014D
+CHECKSUM_A_ADDRESS           = 0x014E
+CHECKSUM_B_ADDRESS           = 0x014F