mirror of
				https://github.com/Klipper3d/klipper.git
				synced 2025-10-31 18:36:09 +01:00 
			
		
		
		
	Initial commit of source code.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
		
							
								
								
									
										212
									
								
								scripts/avrsim.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										212
									
								
								scripts/avrsim.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,212 @@ | ||||
| #!/usr/bin/env python | ||||
| # Script to interact with simulavr by simulating a serial port. | ||||
| # | ||||
| # Copyright (C) 2015  Kevin O'Connor <kevin@koconnor.net> | ||||
| # | ||||
| # This file may be distributed under the terms of the GNU GPLv3 license. | ||||
|  | ||||
| import sys, optparse, os, pty, select, fcntl, termios, traceback, errno | ||||
| import pysimulavr | ||||
|  | ||||
| SERIALBITS = 10 # 8N1 = 1 start, 8 data, 1 stop | ||||
|  | ||||
| # Class to read serial data from AVR serial transmit pin. | ||||
| class SerialRxPin(pysimulavr.PySimulationMember, pysimulavr.Pin): | ||||
|     def __init__(self, baud): | ||||
|         pysimulavr.Pin.__init__(self) | ||||
|         pysimulavr.PySimulationMember.__init__(self) | ||||
|         self.sc = pysimulavr.SystemClock.Instance() | ||||
|         self.delay = 10**9 / baud | ||||
|         self.current = 0 | ||||
|         self.pos = -1 | ||||
|         self.queue = "" | ||||
|     def SetInState(self, pin): | ||||
|         pysimulavr.Pin.SetInState(self, pin) | ||||
|         self.state = pin.outState | ||||
|         if self.pos < 0 and pin.outState == pin.LOW: | ||||
|             self.pos = 0 | ||||
|             self.sc.Add(self) | ||||
|     def DoStep(self, trueHwStep): | ||||
|         ishigh = self.state == self.HIGH | ||||
|         self.current |= ishigh << self.pos | ||||
|         self.pos += 1 | ||||
|         if self.pos == 1: | ||||
|             return int(self.delay * 1.5) | ||||
|         if self.pos >= SERIALBITS: | ||||
|             self.queue += chr((self.current >> 1) & 0xff) | ||||
|             self.pos = -1 | ||||
|             self.current = 0 | ||||
|             return -1 | ||||
|         return self.delay | ||||
|     def popChars(self): | ||||
|         d = self.queue | ||||
|         self.queue = "" | ||||
|         return d | ||||
|  | ||||
| # Class to send serial data to AVR serial receive pin. | ||||
| class SerialTxPin(pysimulavr.PySimulationMember, pysimulavr.Pin): | ||||
|     MAX_QUEUE = 64 | ||||
|     def __init__(self, baud): | ||||
|         pysimulavr.Pin.__init__(self) | ||||
|         pysimulavr.PySimulationMember.__init__(self) | ||||
|         self.SetPin('H') | ||||
|         self.sc = pysimulavr.SystemClock.Instance() | ||||
|         self.delay = 10**9 / baud | ||||
|         self.current = 0 | ||||
|         self.pos = 0 | ||||
|         self.queue = "" | ||||
|     def DoStep(self, trueHwStep): | ||||
|         if not self.pos: | ||||
|             if not self.queue: | ||||
|                 return -1 | ||||
|             self.current = (ord(self.queue[0]) << 1) | 0x200 | ||||
|             self.queue = self.queue[1:] | ||||
|         newstate = 'L' | ||||
|         if self.current & (1 << self.pos): | ||||
|             newstate = 'H' | ||||
|         self.SetPin(newstate) | ||||
|         self.pos += 1 | ||||
|         if self.pos >= SERIALBITS: | ||||
|             self.pos = 0 | ||||
|         return self.delay | ||||
|     def needChars(self): | ||||
|         if len(self.queue) > self.MAX_QUEUE / 2: | ||||
|             return 0 | ||||
|         return self.MAX_QUEUE - len(self.queue) | ||||
|     def pushChars(self, c): | ||||
|         queueEmpty = not self.queue | ||||
|         self.queue += c | ||||
|         if queueEmpty: | ||||
|             self.sc.Add(self) | ||||
|  | ||||
| # Support for creating VCD trace files | ||||
| class Tracing: | ||||
|     def __init__(self, filename, signals): | ||||
|         self.filename = filename | ||||
|         self.signals = signals | ||||
|         if not signals: | ||||
|             self.dman = None | ||||
|             return | ||||
|         self.dman = pysimulavr.DumpManager.Instance() | ||||
|         self.dman.SetSingleDeviceApp() | ||||
|     def show_help(self): | ||||
|         ostr = pysimulavr.ostringstream() | ||||
|         self.dman.save(ostr) | ||||
|         sys.stdout.write(ostr.str()) | ||||
|         sys.exit(1) | ||||
|     def load_options(self): | ||||
|         if self.dman is None: | ||||
|             return | ||||
|         if self.signals.strip() == '?': | ||||
|             self.show_help() | ||||
|         sigs = "\n".join(["+ " + s for s in self.signals.split(',')]) | ||||
|         self.dman.addDumpVCD(self.filename, sigs, "ns", False, False) | ||||
|     def start(self): | ||||
|         if self.dman is not None: | ||||
|             self.dman.start() | ||||
|     def finish(self): | ||||
|         if self.dman is not None: | ||||
|             self.dman.stopApplication() | ||||
|  | ||||
| # Support for creating a pseudo-tty for emulating a serial port | ||||
| def create_pty(ptyname): | ||||
|     mfd, sfd = pty.openpty() | ||||
|     try: | ||||
|         os.unlink(ptyname) | ||||
|     except os.error: | ||||
|         pass | ||||
|     os.symlink(os.ttyname(sfd), ptyname) | ||||
|     fcntl.fcntl(mfd, fcntl.F_SETFL | ||||
|                 , fcntl.fcntl(mfd, fcntl.F_GETFL) | os.O_NONBLOCK) | ||||
|     old = termios.tcgetattr(mfd) | ||||
|     old[3] = old[3] & ~termios.ECHO | ||||
|     termios.tcsetattr(mfd, termios.TCSADRAIN, old) | ||||
|     return mfd | ||||
|  | ||||
| def main(): | ||||
|     usage = "%prog [options] <program.elf>" | ||||
|     opts = optparse.OptionParser(usage) | ||||
|     opts.add_option("-m", "--machine", type="string", dest="machine", | ||||
|                     default="atmega644", help="type of AVR machine to simulate") | ||||
|     opts.add_option("-s", "--speed", type="int", dest="speed", default=8000000, | ||||
|                     help="machine speed") | ||||
|     opts.add_option("-b", "--baud", type="int", dest="baud", default=38400, | ||||
|                     help="baud rate of the emulated serial port") | ||||
|     opts.add_option("-t", "--trace", type="string", dest="trace", | ||||
|                     help="signals to trace (? for help)") | ||||
|     opts.add_option("-p", "--port", type="string", dest="port", | ||||
|                     default="/tmp/pseudoserial", | ||||
|                     help="pseudo-tty device to create for serial port") | ||||
|     deffile = os.path.splitext(os.path.basename(sys.argv[0]))[0] + ".vcd" | ||||
|     opts.add_option("-f", "--tracefile", type="string", dest="tracefile", | ||||
|                     default=deffile, help="filename to write signal trace to") | ||||
|     options, args = opts.parse_args() | ||||
|     if len(args) != 1: | ||||
|         opts.error("Incorrect number of arguments") | ||||
|     elffile = args[0] | ||||
|     proc = options.machine | ||||
|     ptyname = options.port | ||||
|     speed = options.speed | ||||
|     baud = options.baud | ||||
|  | ||||
|     # launch simulator | ||||
|     sc = pysimulavr.SystemClock.Instance() | ||||
|     trace = Tracing(options.tracefile, options.trace) | ||||
|     dev = pysimulavr.AvrFactory.instance().makeDevice(proc) | ||||
|     dev.Load(elffile) | ||||
|     dev.SetClockFreq(10**9 / speed) | ||||
|     sc.Add(dev) | ||||
|     trace.load_options() | ||||
|  | ||||
|     # Setup rx pin | ||||
|     rxpin = SerialRxPin(baud) | ||||
|     net = pysimulavr.Net() | ||||
|     net.Add(rxpin) | ||||
|     net.Add(dev.GetPin("D1")) | ||||
|  | ||||
|     # Setup tx pin | ||||
|     txpin = SerialTxPin(baud) | ||||
|     net2 = pysimulavr.Net() | ||||
|     net2.Add(dev.GetPin("D0")) | ||||
|     net2.Add(txpin) | ||||
|  | ||||
|     # Display start banner | ||||
|     msg = "Starting AVR simulation: machine=%s speed=%d\n" % (proc, speed) | ||||
|     msg += "Serial: port=%s baud=%d\n" % (ptyname, baud) | ||||
|     if options.trace: | ||||
|         msg += "Trace file: %s\n" % (options.tracefile,) | ||||
|     sys.stdout.write(msg) | ||||
|     sys.stdout.flush() | ||||
|  | ||||
|     # Create terminal device | ||||
|     fd = create_pty(ptyname) | ||||
|  | ||||
|     # Run loop | ||||
|     try: | ||||
|         trace.start() | ||||
|         while 1: | ||||
|             starttime = sc.GetCurrentTime() | ||||
|             r = sc.RunTimeRange(speed/1000) | ||||
|             endtime = sc.GetCurrentTime() | ||||
|             if starttime == endtime: | ||||
|                 break | ||||
|             d = rxpin.popChars() | ||||
|             if d: | ||||
|                 os.write(fd, d) | ||||
|             txsize = txpin.needChars() | ||||
|             if txsize: | ||||
|                 res = select.select([fd], [], [], 0) | ||||
|                 if res[0]: | ||||
|                     try: | ||||
|                         d = os.read(fd, txsize) | ||||
|                     except os.error, e: | ||||
|                         if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK): | ||||
|                             continue | ||||
|                         break | ||||
|                     txpin.pushChars(d) | ||||
|         trace.finish() | ||||
|     finally: | ||||
|         os.unlink(ptyname) | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
		Reference in New Issue
	
	Block a user