Getting closer to Bluetooth extraction.
[goodfet] / client / GoodFET.py
1 #!/usr/bin/env python
2 # GoodFET Client Library
3
4 # (C) 2009 Travis Goodspeed <travis at radiantmachines.com>
5 #
6 # This code is being rewritten and refactored.  You've been warned!
7
8 import sys, time, string, cStringIO, struct, glob, os;
9 import sqlite3;
10
11 fmt = ("B", "<H", None, "<L")
12
13 def getClient(name="GoodFET"):
14     import GoodFET, GoodFETCC, GoodFETAVR, GoodFETSPI, GoodFETMSP430, GoodFETNRF, GoodFETCCSPI;
15     if(name=="GoodFET" or name=="monitor"): return GoodFET.GoodFET();
16     elif name=="cc" or name=="cc51": return GoodFETCC.GoodFETCC();
17     elif name=="cc2420" or name=="ccspi": return GoodFETCCSPI.GoodFETCCSPI();
18     elif name=="avr": return GoodFETAVR.GoodFETAVR();
19     elif name=="spi": return GoodFETSPI.GoodFETSPI();
20     elif name=="msp430": return GoodFETMSP430.GoodFETMSP430();
21     elif name=="nrf": return GoodFETNRF.GoodFETNRF();
22     
23     print "Unsupported target: %s" % name;
24     sys.exit(0);
25
26 class SymbolTable:
27     """GoodFET Symbol Table"""
28     db=sqlite3.connect(":memory:");
29     
30     def __init__(self, *args, **kargs):
31         self.db.execute("create table if not exists symbols(adr,name,memory,size,comment);");
32     def get(self,name):
33         self.db.commit();
34         c=self.db.cursor();
35         try:
36             c.execute("select adr,memory from symbols where name=?",(name,));
37             for row in c:
38                 #print "Found it.";
39                 sys.stdout.flush();
40                 return row[0];
41             #print "No dice.";
42         except:# sqlite3.OperationalError:
43             #print "SQL error.";
44             return eval(name);
45         return eval(name);
46     def define(self,adr,name,comment="",memory="vn",size=16):
47         self.db.execute("insert into symbols(adr,name,memory,size,comment)"
48                         "values(?,?,?,?,?);", (
49                 adr,name,memory,size,comment));
50         #print "Set %s=%s." % (name,adr);
51 class GoodFETbtser:
52     """py-bluez class for emulating py-serial."""
53     def __init__(self,watchaddr):
54         import bluetooth;
55         while watchaddr==None or watchaddr=="none":
56             print "performing inquiry..."
57             nearby_devices = bluetooth.discover_devices(lookup_names = True)
58             print "found %d devices" % len(nearby_devices)
59             for addr, name in nearby_devices:
60                 print "  %s - '%s'" % (addr, name)
61                 if name=='FireFly-A6BD':
62                     watchaddr=addr;
63         print "Identified GoodFET at %s" % watchaddr;
64
65         # BlueFET doesn't run the Service Discovery Protocol.
66         # Instead we manually use the portnumber.
67         port=1;
68         
69         print "Connecting to %s on port %i." % (watchaddr, port);
70         sock=bluetooth.BluetoothSocket(bluetooth.RFCOMM);
71         self.sock=sock;
72         sock.connect((watchaddr,port));
73         sock.settimeout(10);  #IMPORTANT Must be patient.
74     def write(self,msg):
75         """Send traffic."""
76         return self.sock.send(msg);
77     def read(self,len):
78         """Read traffic."""
79         return self.sock.recv(len);
80 class GoodFET:
81     """GoodFET Client Library"""
82
83     besilent=0;
84     app=0;
85     verb=0;
86     count=0;
87     data="";
88     verbose=False
89     
90     GLITCHAPP=0x71;
91     MONITORAPP=0x00;
92     symbols=SymbolTable();
93     
94     def __init__(self, *args, **kargs):
95         self.data=[0];
96     def getConsole(self):
97         from GoodFETConsole import GoodFETConsole;
98         return GoodFETConsole(self);
99     def name2adr(self,name):
100         return self.symbols.get(name);
101     def timeout(self):
102         print "timeout\n";
103     def serInit(self, port=None, timeout=2, attemptlimit=None):
104         """Open a serial port of some kind."""
105         self.pyserInit(port,timeout,attemptlimit);
106         #self.btInit(port,timeout,attemptlimit);
107     def btInit(self, port, timeout, attemptlimit):
108         """Open a bluetooth port.""";
109         self.verbose=True;
110         self.serialport=GoodFETbtser(port);
111     def pyserInit(self, port, timeout, attemptlimit):
112         """Open the serial port"""
113         # Make timeout None to wait forever, 0 for non-blocking mode.
114         import serial;
115         
116         if os.name=='nt' and sys.version.find('64 bit')!=-1:
117             print "WARNING: PySerial requires a 32-bit Python build in Windows.";
118         
119         if port is None and os.environ.get("GOODFET")!=None:
120             glob_list = glob.glob(os.environ.get("GOODFET"));
121             if len(glob_list) > 0:
122                 port = glob_list[0];
123             else:
124                 port = os.environ.get("GOODFET");
125         if port is None:
126             glob_list = glob.glob("/dev/tty.usbserial*");
127             if len(glob_list) > 0:
128                 port = glob_list[0];
129         if port is None:
130             glob_list = glob.glob("/dev/ttyUSB*");
131             if len(glob_list) > 0:
132                 port = glob_list[0];
133         if port is None:
134             glob_list = glob.glob("/dev/ttyU0");
135             if len(glob_list) > 0:
136                 port = glob_list[0];
137         if port is None and os.name=='nt':
138             from scanwin32 import winScan;
139             scan=winScan();
140             for order,comport,desc,hwid in sorted(scan.comports()):
141                 try:
142                     if hwid.index('FTDI')==0:
143                         port=comport;
144                         #print "Using FTDI port %s" % port
145                 except:
146                     #Do nothing.
147                     a=1;
148         
149         baud=115200;
150         if(os.environ.get("platform")=='arduino'):
151             baud=19200; #Slower, for now.
152         self.serialport = serial.Serial(
153             port,
154             #9600,
155             baud,
156             parity = serial.PARITY_NONE,
157             timeout=timeout
158             )
159         
160         self.verb=0;
161         attempts=0;
162         connected=0;
163         while connected==0:
164             while self.verb!=0x7F or self.data!="http://goodfet.sf.net/":
165             #while self.data!="http://goodfet.sf.net/":
166                 #print "'%s'!=\n'%s'" % (self.data,"http://goodfet.sf.net/");
167                 if attemptlimit is not None and attempts >= attemptlimit:
168                     return
169                 elif attempts>2:
170                     print "Resyncing.";
171                 self.serialport.flushInput()
172                 self.serialport.flushOutput()
173                 
174                 #TelosB reset, prefer software to I2C SPST Switch.
175                 if(os.environ.get("platform")=='telosb'):
176                     #print "TelosB Reset";
177                     self.telosBReset();
178                 else:
179                     #Explicitly set RTS and DTR to halt board.
180                     self.serialport.setRTS(1);
181                     self.serialport.setDTR(1);
182                     #Drop DTR, which is !RST, low to begin the app.
183                     self.serialport.setDTR(0);
184                 
185                 #self.serialport.write(chr(0x80));
186                 #self.serialport.write(chr(0x80));
187                 #self.serialport.write(chr(0x80));
188                 #self.serialport.write(chr(0x80));
189                 
190                 
191                 #self.serialport.flushInput()
192                 #self.serialport.flushOutput()
193                 #time.sleep(60);
194                 attempts=attempts+1;
195                 self.readcmd(); #Read the first command.
196                 #print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data);
197             #Here we have a connection, but maybe not a good one.
198             #print "We have a connection."
199             connected=1;
200             olds=self.infostring();
201             clocking=self.monitorclocking();
202             #if(os.environ.get("platform")!='arduino'):
203             for foo in range(1,30):
204                 if not self.monitorecho():
205                     if self.verbose:
206                         print "Comm error on %i try, resyncing out of %s." % (foo,
207                                                                               clocking);
208                         connected=0;
209                         break;
210         if self.verbose: print "Connected after %02i attempts." % attempts;
211         self.mon_connected();
212         self.serialport.setTimeout(12);
213     def serClose(self):
214         self.serialport.close();
215     def telosSetSCL(self, level):
216         self.serialport.setRTS(not level)
217     def telosSetSDA(self, level):
218         self.serialport.setDTR(not level)
219
220     def telosI2CStart(self):
221         self.telosSetSDA(1)
222         self.telosSetSCL(1)
223         self.telosSetSDA(0)
224
225     def telosI2CStop(self):
226         self.telosSetSDA(0)
227         self.telosSetSCL(1)
228         self.telosSetSDA(1)
229
230     def telosI2CWriteBit(self, bit):
231         self.telosSetSCL(0)
232         self.telosSetSDA(bit)
233         time.sleep(2e-6)
234         self.telosSetSCL(1)
235         time.sleep(1e-6)
236         self.telosSetSCL(0)
237
238     def telosI2CWriteByte(self, byte):
239         self.telosI2CWriteBit( byte & 0x80 );
240         self.telosI2CWriteBit( byte & 0x40 );
241         self.telosI2CWriteBit( byte & 0x20 );
242         self.telosI2CWriteBit( byte & 0x10 );
243         self.telosI2CWriteBit( byte & 0x08 );
244         self.telosI2CWriteBit( byte & 0x04 );
245         self.telosI2CWriteBit( byte & 0x02 );
246         self.telosI2CWriteBit( byte & 0x01 );
247         self.telosI2CWriteBit( 0 );  # "acknowledge"
248
249     def telosI2CWriteCmd(self, addr, cmdbyte):
250         self.telosI2CStart()
251         self.telosI2CWriteByte( 0x90 | (addr << 1) )
252         self.telosI2CWriteByte( cmdbyte )
253         self.telosI2CStop()
254
255     def telosBReset(self,invokeBSL=0):
256         # "BSL entry sequence at dedicated JTAG pins"
257         # rst !s0: 0 0 0 0 1 1
258         # tck !s1: 1 0 1 0 0 1
259         #   s0|s1: 1 3 1 3 2 0
260
261         # "BSL entry sequence at shared JTAG pins"
262         # rst !s0: 0 0 0 0 1 1
263         # tck !s1: 0 1 0 1 1 0
264         #   s0|s1: 3 1 3 1 0 2
265
266         if invokeBSL:
267             self.telosI2CWriteCmd(0,1)
268             self.telosI2CWriteCmd(0,3)
269             self.telosI2CWriteCmd(0,1)
270             self.telosI2CWriteCmd(0,3)
271             self.telosI2CWriteCmd(0,2)
272             self.telosI2CWriteCmd(0,0)
273         else:
274             self.telosI2CWriteCmd(0,3)
275             self.telosI2CWriteCmd(0,2)
276
277         # This line was not defined inside the else: block, not sure where it
278         # should be however
279         self.telosI2CWriteCmd(0,0)
280         time.sleep(0.250)       #give MSP430's oscillator time to stabilize
281         self.serialport.flushInput()  #clear buffers
282
283
284     def getbuffer(self,size=0x1c00):
285         writecmd(0,0xC2,[size&0xFF,(size>>16)&0xFF]);
286         print "Got %02x%02x buffer size." % (self.data[1],self.data[0]);
287     def writecmd(self, app, verb, count=0, data=[]):
288         """Write a command and some data to the GoodFET."""
289         self.serialport.write(chr(app));
290         self.serialport.write(chr(verb));
291         
292         #if data!=None:
293         #    count=len(data); #Initial count ignored.
294         
295         #print "TX %02x %02x %04x" % (app,verb,count);
296         
297         #little endian 16-bit length
298         self.serialport.write(chr(count&0xFF));
299         self.serialport.write(chr(count>>8));
300
301         if self.verbose:
302             print "Tx: ( 0x%02x, 0x%02x, 0x%04x )" % ( app, verb, count )
303         
304         #print "count=%02x, len(data)=%04x" % (count,len(data));
305         
306         if count!=0:
307             if(isinstance(data,list)):
308                 for i in range(0,count):
309                 #print "Converting %02x at %i" % (data[i],i)
310                     data[i]=chr(data[i]);
311             #print type(data);
312             outstr=''.join(data);
313             self.serialport.write(outstr);
314         if not self.besilent:
315             return self.readcmd()
316         else:
317             return []
318
319     def readcmd(self):
320         """Read a reply from the GoodFET."""
321         while 1:#self.serialport.inWaiting(): # Loop while input data is available
322             try:
323                 #print "Reading...";
324                 self.app=ord(self.serialport.read(1));
325                 #print "APP=%02x" % self.app;
326                 self.verb=ord(self.serialport.read(1));
327                 
328                 #Fixes an obscure bug in the TelosB.
329                 if self.app==0x00:
330                     while self.verb==0x00:
331                         self.verb=ord(self.serialport.read(1));
332                 
333                 #print "VERB=%02x" % self.verb;
334                 self.count=(
335                     ord(self.serialport.read(1))
336                     +(ord(self.serialport.read(1))<<8)
337                     );
338
339                 #if self.verbose:
340                 #print "Rx: ( 0x%02x, 0x%02x, 0x%04x )" % ( self.app, self.verb, self.count )
341             
342                 #Debugging string; print, but wait.
343                 if self.app==0xFF:
344                     if self.verb==0xFF:
345                         print "# DEBUG %s" % self.serialport.read(self.count)
346                     elif self.verb==0xFE:
347                         print "# DEBUG 0x%x" % struct.unpack(fmt[self.count-1], self.serialport.read(self.count))[0]
348                     elif self.verb==0xFD:
349                         #Do nothing, just wait so there's no timeout.
350                         print "# NOP.";
351                         
352                     sys.stdout.flush();
353                 else:
354                     self.data=self.serialport.read(self.count);
355                     return self.data;
356             except TypeError:
357                 if self.connected:
358                     print "Warning: waiting for serial read timed out (most likely).";
359                     #print "This shouldn't happen after syncing.  Exiting for safety.";                    
360                     #sys.exit(-1)
361                 return self.data;
362     #Glitching stuff.
363     def glitchApp(self,app):
364         """Glitch into a device by its application."""
365         self.data=[app&0xff];
366         self.writecmd(self.GLITCHAPP,0x80,1,self.data);
367         #return ord(self.data[0]);
368     def glitchVerb(self,app,verb,data):
369         """Glitch during a transaction."""
370         if data==None: data=[];
371         self.data=[app&0xff, verb&0xFF]+data;
372         self.writecmd(self.GLITCHAPP,0x81,len(self.data),self.data);
373         #return ord(self.data[0]);
374     def glitchstart(self):
375         """Glitch into the AVR application."""
376         self.glitchVerb(self.APP,0x20,None);
377     def glitchstarttime(self):
378         """Measure the timer of the START verb."""
379         return self.glitchTime(self.APP,0x20,None);
380     def glitchTime(self,app,verb,data):
381         """Time the execution of a verb."""
382         if data==None: data=[];
383         self.data=[app&0xff, verb&0xFF]+data;
384         print "Timing app %02x verb %02x." % (app,verb);
385         self.writecmd(self.GLITCHAPP,0x82,len(self.data),self.data);
386         time=ord(self.data[0])+(ord(self.data[1])<<8);
387         print "Timed to be %i." % time;
388         return time;
389     def glitchVoltages(self,low=0x0880, high=0x0fff):
390         """Set glitching voltages. (0x0fff is max.)"""
391         self.data=[low&0xff, (low>>8)&0xff,
392                    high&0xff, (high>>8)&0xff];
393         self.writecmd(self.GLITCHAPP,0x90,4,self.data);
394         #return ord(self.data[0]);
395     def glitchRate(self,count=0x0800):
396         """Set glitching count period."""
397         self.data=[count&0xff, (count>>8)&0xff];
398         self.writecmd(self.GLITCHAPP,0x91,2,
399                       self.data);
400         #return ord(self.data[0]);
401     
402     
403     #Monitor stuff
404     def silent(self,s=0):
405         """Transmissions halted when 1."""
406         self.besilent=s;
407         print "besilent is %i" % self.besilent;
408         self.writecmd(0,0xB0,1,[s]);
409     connected=0;
410     def mon_connected(self):
411         """Announce to the monitor that the connection is good."""
412         self.connected=1;
413         self.writecmd(0,0xB1,0,[]);
414     def out(self,byte):
415         """Write a byte to P5OUT."""
416         self.writecmd(0,0xA1,1,[byte]);
417     def dir(self,byte):
418         """Write a byte to P5DIR."""
419         self.writecmd(0,0xA0,1,[byte]);
420     def call(self,adr):
421         """Call to an address."""
422         self.writecmd(0,0x30,2,
423                       [adr&0xFF,(adr>>8)&0xFF]);
424     def execute(self,code):
425         """Execute supplied code."""
426         self.writecmd(0,0x31,2,#len(code),
427                       code);
428     def MONpeek8(self,address):
429         """Read a byte of memory from the monitor."""
430         self.data=[address&0xff,address>>8];
431         self.writecmd(0,0x02,2,self.data);
432         #self.readcmd();
433         return ord(self.data[0]);
434     def MONpeek16(self,address):
435         """Read a word of memory from the monitor."""
436         return self.MONpeek8(address)+(self.MONpeek8(address+1)<<8);
437     def peek(self,address):
438         """Read a word of memory from the monitor."""
439         return self.MONpeek8(address)+(self.MONpeek8(address+1)<<8);
440     def eeprompeek(self,address):
441         """Read a word of memory from the monitor."""
442         print "EEPROM peeking not supported for the monitor.";
443         #return self.MONpeek8(address)+(self.MONpeek8(address+1)<<8);
444     def peekbysym(self,name):
445         """Read a value by its symbol name."""
446         #TODO include memory in symbol.
447         reg=self.symbols.get(name);
448         return self.peek8(reg,"data");
449     def pokebysym(self,name,val):
450         """Write a value by its symbol name."""
451         #TODO include memory in symbol.
452         reg=self.symbols.get(name);
453         return self.pokebyte(reg,val);
454     def pokebyte(self,address,value,memory="vn"):
455         """Set a byte of memory by the monitor."""
456         self.data=[address&0xff,address>>8,value];
457         self.writecmd(0,0x03,3,self.data);
458         return ord(self.data[0]);
459     def poke16(self,address,value):
460         """Set a word of memory by the monitor."""
461         self.pokebyte(address,value&0xFF);
462         self.pokebyte(address,(value>>8)&0xFF);
463         return value;
464     def setsecret(self,value):
465         """Set a secret word for later retreival.  Used by glitcher."""
466         #self.eeprompoke(0,value);
467         #self.eeprompoke(1,value);
468         print "Secret setting is not yet suppored for this target.";
469         print "Aborting.";
470         
471     def getsecret(self):
472         """Get a secret word.  Used by glitcher."""
473         #self.eeprompeek(0);
474         print "Secret getting is not yet suppored for this target.";
475         print "Aborting.";
476         sys.exit();
477     
478     def dumpmem(self,begin,end):
479         i=begin;
480         while i<end:
481             print "%04x %04x" % (i, self.MONpeek16(i));
482             i+=2;
483     def monitor_ram_pattern(self):
484         """Overwrite all of RAM with 0xBEEF."""
485         self.writecmd(0,0x90,0,self.data);
486         return;
487     def monitor_ram_depth(self):
488         """Determine how many bytes of RAM are unused by looking for 0xBEEF.."""
489         self.writecmd(0,0x91,0,self.data);
490         return ord(self.data[0])+(ord(self.data[1])<<8);
491     
492     #Baud rates.
493     baudrates=[115200, 
494                9600,
495                19200,
496                38400,
497                57600,
498                115200];
499     def setBaud(self,baud):
500         """Change the baud rate.  TODO fix this."""
501         rates=self.baudrates;
502         self.data=[baud];
503         print "Changing FET baud."
504         self.serialport.write(chr(0x00));
505         self.serialport.write(chr(0x80));
506         self.serialport.write(chr(1));
507         self.serialport.write(chr(baud));
508         
509         print "Changed host baud."
510         self.serialport.setBaudrate(rates[baud]);
511         time.sleep(1);
512         self.serialport.flushInput()
513         self.serialport.flushOutput()
514         
515         print "Baud is now %i." % rates[baud];
516         return;
517     def readbyte(self):
518         return ord(self.serialport.read(1));
519     def findbaud(self):
520         for r in self.baudrates:
521             print "\nTrying %i" % r;
522             self.serialport.setBaudrate(r);
523             #time.sleep(1);
524             self.serialport.flushInput()
525             self.serialport.flushOutput()
526             
527             for i in range(1,10):
528                 self.readbyte();
529             
530             print "Read %02x %02x %02x %02x" % (
531                 self.readbyte(),self.readbyte(),self.readbyte(),self.readbyte());
532     def monitortest(self):
533         """Self-test several functions through the monitor."""
534         print "Performing monitor self-test.";
535         self.monitorclocking();
536         for f in range(0,3000):
537             a=self.MONpeek16(0x0c00);
538             b=self.MONpeek16(0x0c02);
539             if a!=0x0c04 and a!=0x0c06:
540                 print "ERROR Fetched %04x, %04x" % (a,b);
541             self.pokebyte(0x0021,0); #Drop LED
542             if self.MONpeek8(0x0021)!=0:
543                 print "ERROR, P1OUT not cleared.";
544             self.pokebyte(0x0021,1); #Light LED
545             if not self.monitorecho():
546                 print "Echo test failed.";
547         print "Self-test complete.";
548         self.monitorclocking();
549     def monitorecho(self):
550         data="The quick brown fox jumped over the lazy dog.";
551         self.writecmd(self.MONITORAPP,0x81,len(data),data);
552         if self.data!=data:
553             print "Comm error recognized by monitorecho(), got:\n%s" % self.data;
554             return 0;
555         return 1;
556
557     def monitor_info(self):
558         print "GoodFET with %s MCU" % self.infostring();
559         print "Clocked at %s" % self.monitorclocking();
560         return 1;
561
562     def monitor_list_apps(self, full=False): 
563         self.monitor_info()
564         old_value = self.besilent
565         self.besilent = True    # turn off automatic call to readcmd
566         self.writecmd(self.MONITORAPP, 0x82, 1, [int(full)]);
567         self.besilent = old_value
568         
569         # read the build date string 
570         self.readcmd()
571         print "Build Date: %s" % self.data
572         print "Firmware apps:"
573         while True:
574             self.readcmd()
575             if self.count == 0:
576                 break
577             print self.data
578         return 1;
579
580     def monitorclocking(self):
581         """Return the 16-bit clocking value."""
582         return "0x%04x" % self.monitorgetclock();
583     
584     def monitorsetclock(self,clock):
585         """Set the clocking value."""
586         self.MONpoke16(0x56, clock);
587     def monitorgetclock(self):
588         """Get the clocking value."""
589         if(os.environ.get("platform")=='arduino'):
590             return 0xDEAD;
591         #Check for MSP430 before peeking this.
592         return self.MONpeek16(0x56);
593     # The following functions ought to be implemented in
594     # every client.
595     
596     def infostring(self):
597         if(os.environ.get("platform")=='arduino'):
598             return "Arduino";
599         else:
600             a=self.MONpeek8(0xff0);
601             b=self.MONpeek8(0xff1);
602             return "%02x%02x" % (a,b);
603     def lock(self):
604         print "Locking Unsupported.";
605     def erase(self):
606         print "Erasure Unsupported.";
607     def setup(self):
608         return;
609     def start(self):
610         return;
611     def test(self):
612         print "Unimplemented.";
613         return;
614     def status(self):
615         print "Unimplemented.";
616         return;
617     def halt(self):
618         print "Unimplemented.";
619         return;
620     def resume(self):
621         print "Unimplemented.";
622         return;
623     def getpc(self):
624         print "Unimplemented.";
625         return 0xdead;
626     def flash(self,file):
627         """Flash an intel hex file to code memory."""
628         print "Flash not implemented.";
629     def dump(self,file,start=0,stop=0xffff):
630         """Dump an intel hex file from code memory."""
631         print "Dump not implemented.";
632     def peek32(self,address, memory="vn"):
633         """Peek 32 bits."""
634         return (self.peek16(address,memory)+
635                 (self.peek16(address+2,memory)<<16));
636     def peek16(self,address, memory="vn"):
637         """Peek 16 bits of memory."""
638         return (self.peek8(address,memory)+
639                 (self.peek8(address+1,memory)<<8));
640     def peek8(self,address, memory="vn"):
641         """Peek a byte of memory."""
642         return self.MONpeek8(address); #monitor
643     def peekblock(self,address,length,memory="vn"):
644         """Return a block of data."""
645         data=range(0,length);
646         for foo in range(0,length):
647             data[foo]=self.peek8(address+foo,memory);
648         return data;
649     def pokeblock(self,address,bytes,memory="vn"):
650         """Poke a block of a data into memory at an address."""
651         for foo in bytes:
652             self.pokebyte(address,foo,memory);
653             address=address+1;
654         return;
655     def loadsymbols(self):
656         """Load symbols from a file."""
657         return;