CVS: msp430simu gdbserver.py,NONE,1.1 core.py,1.16,1.17

Chris Liechti <[email protected]>
Newsgroups gmane.comp.hardware.texas-instruments.msp430.gcc.cvs
Message-ID <[email protected]>
Update of /cvsroot/mspgcc/msp430simu
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6761/msp430simu

Modified Files:
	core.py 
Added Files:
	gdbserver.py 
Log Message:
- added gdbserver this means that msp430-gdb can connect to this sim as "remote target", currently with similar features as the builtin simulator in gdb, but this one is expandable with python scripts
- bugfixes

--- NEW FILE: gdbserver.py ---
#!/usr/bin/env python
#
# GDB server for the MSP430 simulator. This meas that msp430-gdb can
# connect to the simulator and manipulate the simulated core.
# An unllimited number of breakpoints is supported.
#
# (C) 2002-2004 Chris Liechti <[email protected]>
# this is distributed under a free software license, see license.txt
#
# $Id: gdbserver.py,v 1.1 2005/12/30 00:19:10 cliechti Exp $

import sys, socket, threading, binascii
import Queue
import core
import logging
import time

def checksum(data):
    checksum = 0
    for c in data:
        checksum = (checksum + ord(c)) & 0xff
    return checksum


class BreakpointRunner(threading.Thread):
    def __init__(self, core):
        self.log = logging.getLogger("runner")
        self.core = core
        self.interrupted = False
        self.breakpoints = {}
        self.cmd_queue = Queue.Queue(1)
        threading.Thread.__init__(self)
        self.setName('msp430 core')
        self.setDaemon(1)
        
    def set_breakpoint(self, address):
        self.breakpoints[address] = True

    def remove_breakpoint(self, address):
        if address in self.breakpoints:
            del self.breakpoints[address]
            
    def command(self, cmd, action):
        self.log.info('queing remote command %r' % cmd)
        self.cmd_queue.put((cmd, action))
    
    def interrupt(self):
        self.interrupted = True

    def run(self):
        """worker thread"""
        self.log.debug('worker thread started')
        while True:
            try:
                command, action = self.cmd_queue.get()
                self.log.info('executing remote command %r' % command)
                if command == 'run':
                    self.interrupted = False
                    last_time = time.time()
                    step_delta = 0
                    self.log.info('continuing from 0x%04x (cycle %d)' % (self.core.PC.get(), self.core.cycles))
                    while not self.interrupted:
                        self.core.step()
                        if self.core.PC.get() in self.breakpoints:
                            self.log.info('breakpoint @0x%04x (cycle %d)' % (self.core.PC.get(), self.core.cycles))
                            action()
                            break
                        step_delta += 1
                        if step_delta > 1000:          #after a few steps..
                            #time check is not done at every step for better performance
                            step_delta = 0
                            if time.time() - last_time > 3:     #check time, more than 1s passed?
                                #yes, make a log message so that the user knows we're alive
                                last_time = time.time()
                                self.log.info('still running @0x%04x (cycle %d)' % (self.core.PC.get(), self.core.cycles))
                    else:
                        self.log.info('interrupted @0x%04x (cycle %d)' % (self.core.PC.get(), self.core.cycles))
                        action()
                elif command == 'step':
                    self.log.info('single step @0x%04x (cycle %d)' % (self.core.PC.get(), self.core.cycles))
                    self.core.step()
                    if self.core.PC.get() in self.breakpoints:
                        self.log.info('breakpoint @0x%04x (cycle %d)' % (self.core.PC.get(), self.core.cycles))
                    action()
                else:
                    self.log.error('unknown command %r' % (command, ))
            except:
                self.log.exception('error in runner')

class GDBServer(threading.Thread):
    def __init__(self, core, port = 3333):
        self.core = core
        self.port = port
        threading.Thread.__init__(self)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind( ('localhost', port) )

    def run(self):
        print "gdbserver listening on port %d" % self.port
        self.sock.listen(1)
        while 1:
            conn, addr = self.sock.accept()
            print 'connected by', addr
            GDBClientHandler(self.core, conn).start()


class GDBClientHandler(threading.Thread):
    def __init__(self, core, clientsocket):
        threading.Thread.__init__(self)
        self.setName('gdb remote connection %r' % clientsocket)
        self.clientsocket = clientsocket
        self.netin = clientsocket.makefile("r")
        self.netout = clientsocket.makefile("w")
        self.setDaemon(1)
        self.core = core
        self.log = logging.getLogger("gdbclient")
        self.runner = BreakpointRunner(core)
        self.runner.start()

    def close(self):
        self.log.info("closing...")
        self.netin.close()
        self.netout.close()
        self.clientsocket.close()
        self.log.info("closed")

    #~ def _answer_ok(self):
    def _answer_sigtrap(self):
        self.writePacket("S%02x" % (5,))    #SIGTRAP
        
    def run(self):
        try:
            self.log.info("client loop ready...")
            while 1:
                try:
                    pkt = self.readPacket()
                    self.log.debug('processing remote command %r' % pkt)
                except ValueError:
                    self.netout.write("-")
                    self.netout.flush()
                else:
                    self.netout.write("+")
                    self.netout.flush()
                    if pkt[0] == "?":
                        sig = 0
                        #self.writePacket("T%02x%02x:%04x" % (sig, 0, 0x1234))
                        self.writePacket("S%02x" % (sig,))
                    elif pkt[0] == "c":     #continue
                        if len(pkt) > 1:
                            adr = int(pkt[1:],16)
                            self.core.PC.set(adr)
                        self.runner.command('run', self._answer_sigtrap)
                        #~ self.writePacket("S%02x" % (5,))    #SIGTRAP
                    elif pkt[0] == "D":     #detach
                        self.core.reset()
                    elif pkt[0] == "g":     #Read general registers
                        self.log.debug("Reading device registers")
                        self.writePacket(''.join(["%02x%02x" % (r.get()&0xff, (r.get()>>8)&0xff) for r in self.core.R]))
                    elif pkt[0] == "G":     #write regs
                        self.log.debug("Writing device registers")
                        for n, value in enumerate([int(pkt[i:i+2],16) + int(pkt[i+2:i+4],16)<<8 for i in range(1, 1+16*4, 4)]):
                            self.core.R[n].set(value)
                        self.writePacket("OK")
                    elif pkt[0] == "H":
                        self.writePacket("OK")
                    elif pkt[0] == "k":     #kill request
                        self.core.reset()
                        self.writePacket("OK")
                    elif pkt[0] == "m":     #read memory
                        self.log.debug("Reading device memory")
                        fromadr, length = [int(x, 16) for x in pkt[1:].split(',')]
                        mem = self.core.memory.read(fromadr, length)
                        self.writePacket(''.join(["%02x" % ord(x) for x in mem]))
                    elif pkt[0] == "M":     #write memory
                        self.log.debug("Writing device memory")
                        meta, data = pkt.split(':')
                        fromadr, length = [int(x, 16) for x in meta[1:].split(',')]
                        sdata = ''.join([chr(int(data[i:i+2],16)) for i in range(0,len(data),2)])
                        try:
                            self.core.memory.write(fromadr, sdata)
                        except IOError:
                            self.writePacket("E01") #write error
                        else:
                            self.writePacket("OK")
                    elif pkt[0] == "q":     #remote commands
                        if pkt[1:5] == "Rcmd":
                            cmd = binascii.unhexlify(pkt.split(',')[1]).strip()
                            self.log.info("monitor command: %r" % cmd)
                            if cmd[0:1] == '"': #its a string, execute python code !Security risk!
                                ans = eval(cmd[1:-1])
                                self.writePacket(binascii.hexlify(repr(ans)))
                            #~ elif cmd == 'erase':
                                #~ print "Erasing the device MAIN memory..."
                                #~ self.writePacket("OK")
                            else:
                                self.writePacket("E01")
                        else:
                            self.writePacket("E01") #write error
                    elif pkt[0] == "s":     #single step
                        if len(pkt) > 1:
                            adr = int(pkt[1:],16)
                            self.core.PC.set(adr)
                        self.runner.command('step', self._answer_sigtrap)
                    elif pkt[0] == "Z":     #set break or watchpoint
                        ty, adr, length = pkt[1:].split(',')
                        if ty == '0':
                            self.log.debug("Setting breakpoint")
                            self.runner.set_breakpoint(int(adr,16))
                            self.writePacket("OK")
                        else:
                            self.writePacket("E%02x" % (1,))
                    elif pkt[0] == "z":     #remove break or watchpoint
                        ty, adr, length = pkt[1:].split(',')
                        if ty == '0':
                            self.log.debug("Clearing breakpoint")
                            adr = int(adr,16)
                            if adr in self.runner.breakpoints:
                                self.runner.remove_breakpoint(adr)
                                self.writePacket("OK")
                            else:
                                self.writePacket("E%02x" % (2,))
                        else:
                            self.writePacket("E%02x" % (1,))
                    else:   #command not supported
                        self.log.debug("Unsupported comand %r" % pkt)
                        self.writePacket("")
        finally:
            self.close()

    def readPacket(self):
        self.log.debug("readPacket")
        gdbcommand = 0
        csum = 0
        packet = []
        while 1:
            c = self.netin.read(1)
            if not c: self.close() #EOF
            if c == '\x03':     #ctrl+c
                self.runner.interrupt()
                continue
            #print repr(c),
            if gdbcommand:
                if c == '#':
                    if csum != int(self.netin.read(1) + self.netin.read(1), 16):
                        raise ValueError("wrong checksum")
                    return ''.join(packet)
                else:
                    packet.append(c)
                    csum = (csum + ord(c)) % 256
            else:
                if c == '$':
                    gdbcommand = 1

    def writePacket(self, msg):
        self.log.debug("writePacket(%r)" % msg)
        self.netout.write("$%s#%02x" % (msg, checksum(msg)))
        self.netout.flush()

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    #~ logging.basicConfig(level=logging.DEBUG)
    log = logging.getLogger('trace')
    
    msp430 = core.Core()
    msp430.memory.append(core.Multiplier())
    
    GDBServer(msp430).start()



Index: core.py
===================================================================
RCS file: /cvsroot/mspgcc/msp430simu/core.py,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -w -d -r1.16 -r1.17
--- core.py	29 Dec 2005 21:17:23 -0000	1.16
+++ core.py	30 Dec 2005 00:19:10 -0000	1.17
@@ -1,4 +1,12 @@
 #!/usr/bin/env python
+#
+# MSP430 simulator core.
+#
+# (C) 2002-2004 Chris Liechti <[email protected]>
+# this is distributed under a free software license, see license.txt
+#
+# $Id$
+
 import sys
 import logging
 
@@ -544,6 +552,7 @@
 
     def _set(self, address, value, bytemode=0):
         """quiet set without logging"""
+        address &= 0xffff       #16 bit wrap around
         for p in self.peripherals:
             if address in p:
                 p.set(address, value, bytemode)
@@ -557,6 +566,9 @@
 
     def set(self, address, value, bytemode=0):
         """write value to address"""
+        if address > 0xffff:
+            self.log.error('write outside valid address range (0x%04x)' % (address, ))
+            address &= 0xffff       #16 bit wrap around
         self.log.debug('write 0x%04x <- 0x%04x mode:%s' % (address, value, bytemode and 'b' or 'w'))
         if self.setwatches.has_key(address): self.setwatches[address](address, bytemode, self.memory[address], value)  #call watch
         for a in self.accesswatches: a(self, bytemode, 1, address)
@@ -565,6 +577,7 @@
 
     def _get(self, address, bytemode=0):
         """quiet get without logging"""
+        address &= 0xffff       #16 bit wrap around
         for p in self.peripherals:
             if address in p:
                 value = p.get(address, bytemode)
@@ -578,12 +591,22 @@
 
     def get(self, address, bytemode=0):
         """read value from address"""
+        if address > 0xffff:
+            self.log.error('read outside valid address range (0x%04x)' % (address, ))
+            address &= 0xffff       #16 bit wrap around
         if self.getwatches.has_key(address): self.getwatches[address](address, bytemode, self.memory[address], None)  #call watch
         for a in self.accesswatches: a(self, bytemode, 0, address)
         value = self._get(address, bytemode)
         self.log.debug('read 0x%04x -> 0x%04x mode:%s' % (address, value, bytemode and 'b' or 'w'))
         return value
 
+    def read(self, address, length):
+        return ''.join([chr(self._get(a,1)) for a in range(address, address+length)])
+
+    def write(self, address, data):
+        for n, byte in enumerate(data):
+            self._set(address+n, ord(byte), 1)
+
     def hexline(self, address, width=16):
         """build a tuple with (address, hex values, ascii values)"""
         bytes = [self._get(a, bytemode=1) for a in range(address, address+width)]



-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.