Broadcaster: driving two identical interfaces

Part of the validation of the Gameduino hardware is to run a long test that sets the hardware into a random state, then checks that the hardware and simulator produce the same output.

This is a traditional way of trying to find hardware failure modes that directed testing can miss. Eventually, with enough randomization, any difference between the hardware and the model will show up.

For Gameduino, this is pretty straightforward. There are two classes:

The two classes have almost identical interfaces. This makes it easy to switch between hardware and simulator, as well as making the validation easier.

The randomized test needs to do the same thing to both objects. For example, it might want to write a random byte to a random location in the first 1K of memory:

r = random.randrange(1024)
v = random.randrange(256)
gs.wr(r, v)       # simulator
gh.wr(r, v)       # hardware

This repetition of methods on both gs and gh is needed in many places in the test. Here's a way of avoiding the repetition:

class Broadcaster(object):
    def __init__(self, objs):
        self.objs = objs
    def __getattr__(self, name):
        def bcast(*args):
            return [o.__getattribute__(name)(*args) for o in self.objs]
        return bcast

g = Broadcaster((gs, gh))
g.wr(random.randrange(1024), random.randrange(256))

The Broadcaster object g passes any method invocations down to the objects gs and gh. So now a single method on g results in the identical method on both gs and gh.

Broadcaster does another useful thing: it collects the return values from each method into a list. The randoms use this to collect readbacks from the two models:

>> print gs.rd(0x2800), gh.rd(0x2800)
0x6d 0x6d
>> print g.rd(0x2800)
[0x6d, 0x6d]