Mercurial > lcfOS
changeset 292:534b94b40aa8
Fixup reorganize
line wrap: on
line diff
--- a/kernel/kernel.c3 Sun Nov 24 11:24:15 2013 +0100 +++ b/kernel/kernel.c3 Wed Nov 27 08:06:42 2013 +0100 @@ -1,19 +1,25 @@ module kernel; + import memory; import process; +import scheduler; +import arch; // Main entry point of the kernel: func start() { - process.Init(); - memory.Init(); + process.Init(); + memory.Init(); + + + Process proc = new process.Process(); + + scheduler.queue(proc); } func panic() { - while(true) - { - } + arch.halt(); }
--- a/kernel/make.sh Sun Nov 24 11:24:15 2013 +0100 +++ b/kernel/make.sh Wed Nov 27 08:06:42 2013 +0100 @@ -1,4 +1,4 @@ #!/bin/bash -../python/zcc.py memory.c3 +../python/zcc.py memory.c3 kernel.c3
--- a/kernel/process.c3 Sun Nov 24 11:24:15 2013 +0100 +++ b/kernel/process.c3 Wed Nov 27 08:06:42 2013 +0100 @@ -5,8 +5,12 @@ // process type definition: typedef struct { int id; + int status; } process_t; +// Or, use this list structure: +List<process_t> procs; + // init is the root of all processes: var process_t* init = 0; var int next_pid = 0; @@ -34,4 +38,10 @@ // clean memory } +public process_t* byId(int id) +{ + // Perform lookup + return 0; +} +
--- a/kernel/syscall.c3 Sun Nov 24 11:24:15 2013 +0100 +++ b/kernel/syscall.c3 Wed Nov 27 08:06:42 2013 +0100 @@ -1,9 +1,60 @@ module syscall; +/* + This module handles all the system calls from user space. +*/ + +enum { + SendMsg = 1, + ReceiveMsg = 2, + +} syscall_t; // System call handlers. System calls are made from user space. +func void handle_system_call(int callId, int a, int b, int c, int d) +{ + // Main entry, check what to do here + switch(callId) + { + case SendMsg: + handle_send_msg(); + proc = process.byId(a); + if (not proc) + { + panic(); + } -func void handle_system_call() -{ + proc.setMessage(); + scheduler.current.setState(Sleep); + break; + case ReceiveMsg: + break; + case Reboot: + arch.reboot(); + break; + default: + return NO_SUCH_CALL; + } + + return OK; } +// Handle send message syscall +func void handle_send_msg() +{ + p = process.byId(msg.to_id); + scheduler.attempt(p); +} + +func handle_recv_msg() +{ + // Block until we have a message + currentProc->setState(Sleep); + scheduler.executeNext(); +} + +func handle_reboot() +{ + reboot(); +} +
--- a/python/adi.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - -# Implementation of the ADI (ARM Debug Interface) v5 interface. - -COMPONENT_CLASSES = {0x1: 'ROM table'} - -class Adi: - def __init__(self, iface): - self.iface = iface - def r32(self, address): - return self.iface.read_debug32(address) - def w32(self, address, value): - self.iface.write_debug32(address, value) - def getId(self, offset): - print('reading id from {0:X}'.format(offset)) - pid4 = self.r32(offset + 0xFD0) - #print('pid4', pid4) - pid5 = self.r32(offset + 0xFD4) - pid6 = self.r32(offset + 0xFD8) - pid7 = self.r32(offset + 0xFDC) - pid0 = self.r32(offset + 0xFE0) - pid1 = self.r32(offset + 0xFE4) - pid2 = self.r32(offset + 0xFE8) - pid3 = self.r32(offset + 0xFEC) - cid0 = self.r32(offset + 0xFF0) - cid1 = self.r32(offset + 0xFF4) - cid2 = self.r32(offset + 0xFF8) - cid3 = self.r32(offset + 0xFFC) - pids = [pid0, pid1, pid2, pid3, pid4, pid5, pid6, pid7] - cids = [cid0, cid1, cid2, cid3] - print('cids:', [hex(x) for x in cids], 'pids', [hex(x) for x in pids]) - valid = cid0 == 0xD and (cid1 & 0xF) == 0x0 and cid2 == 0x5 and cid3 == 0xB1 - if valid: - component_class = cid1 >> 4 - else: - print('invalid class') - component_class = 0 - # TODO: use pids - return component_class, pids - - def parseRomTable(self, offset): - assert (offset & 0xFFF) == 0 - component_class, pid = self.getId(offset) - assert component_class == 1 - print('Component class:', COMPONENT_CLASSES[component_class]) - print('memory also on this bus:', self.r32(offset + 0xFCC)) - idx = 0 - entry = self.r32(offset + idx * 4) - while entry != 0: - #print('Entry: {0:X}'.format(entry)) - entryOffset = entry & 0xFFFFF000 - cls, pids = self.getId((offset + entryOffset) & 0xFFFFFFFF) - print('class:', cls) - if cls == 9: - print('Debug block found!') - - idx += 1 - entry = self.r32(offset + idx * 4) - -
--- a/python/bin2c.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -#!/usr/bin/python - -import sys -print(sys.argv) -if len(sys.argv) < 2: - print('Usage: {0} binfile [headerfile]'.format(sys.argv[0])) - sys.exit(-1) - -with open(sys.argv[1], 'rb') as f: - data = f.read() - -s = ', '.join(hex(b) for b in data) -output = 'unsigned char data[] = {{{0}}};'.format(s) -if len(sys.argv) < 3: - print(output) -else: - with open(sys.argv[2], 'w') as f: - f.write(output) -
--- a/python/codegen.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/codegen.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,30 +1,28 @@ import ir -import target +from target import Target from ppci import CompilerError import transform import canon +import registerallocator -# TODO: this class could be target independent: class CodeGenerator: - def __init__(self, outs, target): + """ Generic code generator """ + def __init__(self, target): # TODO: schedule traces in better order. # This is optional! - assert isinstance(tg, target.Target) + assert isinstance(target, Target), target self.target = target - self.ins_sel = ArmInstructionSelector() + self.ins_sel = target.ins_sel self.ra = registerallocator.RegisterAllocator() - self.outs = outs - self.outs.getSection('code').address = 0x08000000 - self.outs.getSection('data').address = 0x20000000 - def generateFunc(self, irfunc): + def generateFunc(self, irfunc, outs): """ Generate code for one function into a frame """ # Cleanup function: transform.removeEmptyBlocks(irfunc) # Create a frame for this function: - frame = ArmFrame(irfunc.name) + frame = self.target.FrameClass(irfunc.name) # Canonicalize the intermediate language: canon.make(irfunc, frame) @@ -34,32 +32,21 @@ self.ra.allocFrame(frame) # TODO: Peep-hole here? - # Can we materialize here?? - # Add label and return and stack adjustment: frame.EntryExitGlue3() # Materialize assembly # Materialize the register allocated instructions into a stream of # real instructions. - frame.lower_to(self.outs) + frame.lower_to(outs) return frame - def generate(self, ircode): + def generate(self, ircode, outs): assert isinstance(ircode, ir.Module) - self.outs.selectSection('code') - # assembly glue to make it work: - # TODO: this must be in source code, not in compiler - self.outs.emit(arm.dcd_ins(Imm32(0x20000678))) # initial SP - self.outs.emit(arm.dcd_ins(Imm32(0x08000009))) # reset vector - self.outs.emit(arm.b_ins(LabelRef('main'))) + outs.selectSection('code') # Munch program into a bunch of frames. One frame per function. # Each frame has a flat list of abstract instructions. # Generate code for all functions: - self.frames = [self.generateFunc(func) for func in ircode.Functions] - - # TODO: fixup references, do this in another way? - self.outs.backpatch() - self.outs.backpatch() # Why two times? + self.frames = [self.generateFunc(func, outs) for func in ircode.Functions] return self.frames
--- a/python/devices.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -import sys -import usb - -# Global device list to which devices are registered. -devices = {} - -def registerDevice(chipId): - """ Decorator to register a device """ - def wrapper(dev): - devices[chipId] = dev - return dev - return wrapper - -# Global interface dictionary. -interfaces = {} - -def registerInterface(vid_pid): - def wrapper(iface): - interfaces[vid_pid] = iface - return iface - return wrapper - -def createInterfaces(): - """ Create a list of detected interfaces """ - ctx = usb.UsbContext() - - # Retrieve all usb devices: - devs = ctx.DeviceList - keys = interfaces.keys() - - # Filter function to filter only registered interfaces: - def filt(usbiface): - return (usbiface.VendorId, usbiface.ProductId) in keys - def buildInterface(usbiface): - key = (usbiface.VendorId, usbiface.ProductId) - iface = interfaces[key] - return iface(usbiface) - return [buildInterface(uif) for uif in filter(filt, devs)] - -class Device: - """ - Base class for a device possibly connected via an interface. - """ - def __init__(self, iface): - # Store the interface through which this device is connected: - assert isinstance(iface, Interface) - self.iface = iface - -class Interface: - """ - Generic interface class. Connected via Usb to a JTAG interface. - Possibly is connected with a certain chip. - """ - def createDevice(self): - """ Try to get the device connected to this interface """ - if self.ChipId in devices: - return devices[self.ChipId](self) - raise STLinkException('No device found!') - -class STLinkException(Exception): - """ Exception used for interfaces and devices """ - pass -
--- a/python/diagramitems.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,437 +0,0 @@ -""" - Contains all blocks that can be used to build models. -""" - -from PyQt4.QtGui import * -from PyQt4.QtCore import * - -def uniqify(name, names): - newname, i = name, 1 - while newname in names: newname, i = name + str(i), i + 1 - return newname - -def enum(**enums): - return type('Enum', (), enums) - -Position = enum(TOP=0, TOP_RIGHT=1, RIGHT=2, BOTTOM_RIGHT=3, BOTTOM=4, BOTTOM_LEFT=5, LEFT=6, TOP_LEFT=7) - -def buildPath(pts): - path = QPainterPath(pts[0]) - for pt in pts[1:]: path.lineTo(pt) - return path - -def equalSpace(n, l, offset=15): - if n == 1: - return [l / 2] - elif n > 1: - return [offset + (l - offset*2)/(n - 1)*i for i in range(n)] - return [] - -class Connection(QGraphicsPathItem): - """ A connection between blocks """ - def __init__(self, fromPort=None, toPort=None): - super(Connection, self).__init__() - self.pos2 = self.fromPort = self.toPort = None - self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape) - pen = QPen(Qt.blue, 2, cap=Qt.RoundCap) - self.setPen(pen) - self.arrowhead = QGraphicsPathItem(self) - self.arrowhead.setPath(buildPath([QPointF(0.0, 0.0), QPointF(-6.0, 10.0), QPointF(6.0, 10.0), QPointF(0.0, 0.0)])) - self.arrowhead.setPen(pen) - self.arrowhead.setBrush(QBrush(pen.color())) - self.vias = [] - self.setFromPort(fromPort) - self.setToPort(toPort) - def getDict(self): - d = {} - d['fromBlock'] = self.fromPort.block.name - d['fromPort'] = self.fromPort.name - d['toBlock'] = self.toPort.block.name - d['toPort'] = self.toPort.name - return d - Dict = property(getDict) - def myDelete(self): - scene = self.scene() - if scene: - self.setFromPort(None) - self.setToPort(None) - scene.removeItem(self) - def setFromPort(self, fromPort): - if self.fromPort: - self.fromPort.posCallbacks.remove(self.setBeginPos) - self.fromPort.connection = None - self.fromPort = fromPort - if self.fromPort: - self.fromPort.connection = self - self.updateLineStukken() - self.fromPort.posCallbacks.append(self.setBeginPos) - def setToPort(self, toPort): - if self.toPort: - self.toPort.posCallbacks.remove(self.setEndPos) - self.toPort.connection = None - self.toPort = toPort - if self.toPort: - self.setEndPos(toPort.scenePos()) - self.toPort.connection = self - self.toPort.posCallbacks.append(self.setEndPos) - def getPos1(self): - if self.fromPort: - return self.fromPort.scenePos() - def setBeginPos(self, pos1): self.updateLineStukken() - def setEndPos(self, endpos): - self.pos2 = endpos - self.updateLineStukken() - def itemChange(self, change, value): - if change == self.ItemSelectedHasChanged: - for via in self.vias: - via.setVisible(value) - return super(Connection, self).itemChange(change, value) - def shape(self): return self.myshape - def updateLineStukken(self): - """ - This algorithm determines the optimal routing of all signals. - TODO: implement nice automatic line router - """ - pos1 = self.getPos1() - pos2 = self.pos2 - if pos1 is None or pos2 is None: - return - scene = self.scene() - vias = [pos1 + QPointF(20, 0)] + self.vias + [pos2 + QPointF(-20, 0)] - if scene: - litem = QGraphicsLineItem() - litem.setFlags(self.ItemIsSelectable) - scene.addItem(litem) - for p1, p2 in zip(vias[:-1], vias[1:]): - line = QLineF(p1, p2) - litem.setLine(line) - citems = scene.collidingItems(litem) - citems = [i for i in citems if type(i) is Block] - scene.removeItem(litem) - pts = [pos1] + vias + [pos2] - self.arrowhead.setPos(pos2) - self.arrowhead.setRotation(90) - p = buildPath(pts) - self.setPath(p) - """ Create a shape outline using the path stroker """ - s = super(Connection, self).shape() - pps = QPainterPathStroker() - pps.setWidth(10) - self.myshape = pps.createStroke(s).simplified() - -class PortItem(QGraphicsPathItem): - """ Represents a port to a subsystem """ - def __init__(self, name, block): - super(PortItem, self).__init__(block) - self.textItem = QGraphicsTextItem(self) - self.connection = None - self.block = block - self.setCursor(QCursor(Qt.CrossCursor)) - self.setPen(QPen(Qt.blue, 2, cap=Qt.RoundCap)) - self.name = name - self.posCallbacks = [] - self.setFlag(self.ItemSendsScenePositionChanges, True) - def getName(self): return self.textItem.toPlainText() - def setName(self, name): - self.textItem.setPlainText(name) - rect = self.textItem.boundingRect() - lw, lh = rect.width(), rect.height() - lx = 3 if type(self) is InputPort else -3 - lw - self.textItem.setPos(lx, -lh / 2) - name = property(getName, setName) - def getDict(self): - return {'name': self.name} - Dict = property(getDict) - def itemChange(self, change, value): - if change == self.ItemScenePositionHasChanged: - for cb in self.posCallbacks: cb(value) - return value - return super(PortItem, self).itemChange(change, value) - -class OutputPort(PortItem): - def __init__(self, name, block, d=10.0): - super(OutputPort, self).__init__(name, block) - self.setPath(buildPath([QPointF(0.0, -d), QPointF(d, 0), QPointF(0.0, d)])) - def mousePressEvent(self, event): - self.scene().startConnection(self) - -class InputPort(PortItem): - def __init__(self, name, block, d=10.0): - super(InputPort, self).__init__(name, block) - self.setPath(buildPath([QPointF(-d, -d), QPointF(0, 0), QPointF(-d, d)])) - -class Handle(QGraphicsEllipseItem): - """ A handle that can be moved by the mouse """ - def __init__(self, dx=10.0, parent=None): - super(Handle, self).__init__(QRectF(-0.5*dx,-0.5*dx,dx,dx), parent) - self.setBrush(QBrush(Qt.white)) - self.setFlags(self.ItemIsMovable) - self.setZValue(1) - self.setVisible(False) - self.setCursor(QCursor(Qt.SizeFDiagCursor)) - def mouseMoveEvent(self, event): - """ Move function without moving the other selected elements """ - p = self.mapToParent(event.pos()) - self.setPos(p) - -class ResizeSelectionHandle(Handle): - def __init__(self, position, block): - super(ResizeSelectionHandle, self).__init__(dx=12, parent=block) - self.position = position - self.block = block - if position in [Position.TOP_LEFT, Position.BOTTOM_RIGHT]: - self.setCursor(QCursor(Qt.SizeFDiagCursor)) - elif position in [Position.TOP_RIGHT, Position.BOTTOM_LEFT]: - self.setCursor(QCursor(Qt.SizeBDiagCursor)) - elif position in [Position.TOP, Position.BOTTOM]: - self.setCursor(QCursor(Qt.SizeVerCursor)) - elif position in [Position.LEFT, Position.RIGHT]: - self.setCursor(QCursor(Qt.SizeHorCursor)) - def mouseMoveEvent(self, event): - self.block.sizerMoveEvent(self, event.scenePos()) - -class Block(QGraphicsRectItem): - """ Represents a block in the diagram. """ - def __init__(self, name='Untitled', parent=None): - super(Block, self).__init__(parent) - self.selectionHandles = [ResizeSelectionHandle(i, self) for i in range(8)] - # Properties of the rectangle: - self.setPen(QPen(Qt.blue, 2)) - self.setBrush(QBrush(Qt.lightGray)) - self.setFlags(self.ItemIsSelectable | self.ItemIsMovable | self.ItemSendsScenePositionChanges) - self.setCursor(QCursor(Qt.PointingHandCursor)) - self.setAcceptHoverEvents(True) - self.label = QGraphicsTextItem(name, self) - self.name = name - # Create corner for resize: - button = QPushButton('+in') - button.clicked.connect(self.newInputPort) - self.buttonItemAddInput = QGraphicsProxyWidget(self) - self.buttonItemAddInput.setWidget(button) - self.buttonItemAddInput.setVisible(False) - button = QPushButton('+out') - button.clicked.connect(self.newOutputPort) - self.buttonItemAddOutput = QGraphicsProxyWidget(self) - self.buttonItemAddOutput.setWidget(button) - self.buttonItemAddOutput.setVisible(False) - # Inputs and outputs of the block: - self.inputs = [] - self.outputs = [] - self.changeSize(2,2) - def editParameters(self): - pd = ParameterDialog(self, self.window()) - pd.exec_() - def newInputPort(self): - names = [i.name for i in self.inputs + self.outputs] - self.addInput(InputPort(uniqify('in', names), self)) - def newOutputPort(self): - names = [i.name for i in self.inputs + self.outputs] - self.addOutput(OutputPort(uniqify('out', names), self)) - def setName(self, name): self.label.setPlainText(name) - def getName(self): return self.label.toPlainText() - name = property(getName, setName) - def getDict(self): - d = {'x': self.scenePos().x(), 'y': self.scenePos().y()} - rect = self.rect() - d.update({'width': rect.width(), 'height': rect.height()}) - d['name'] = self.name - d['inputs'] = [inp.Dict for inp in self.inputs] - d['outputs'] = [outp.Dict for outp in self.outputs] - return d - def setDict(self, d): - self.name = d['name'] - self.setPos(d['x'], d['y']) - self.changeSize(d['width'], d['height']) - for inp in d['inputs']: - self.addInput(InputPort(inp['name'], self)) - for outp in d['outputs']: - self.addOutput(OutputPort(outp['name'], self)) - Dict = property(getDict, setDict) - def addInput(self, i): - self.inputs.append(i) - self.updateSize() - def addOutput(self, o): - self.outputs.append(o) - self.updateSize() - def contextMenuEvent(self, event): - menu = QMenu() - pa = menu.addAction('Parameters') - pa.triggered.connect(self.editParameters) - menu.exec_(event.screenPos()) - def itemChange(self, change, value): - if change == self.ItemSelectedHasChanged: - for child in [self.buttonItemAddInput, self.buttonItemAddOutput]: - child.setVisible(value) - if value: - self.repositionAndShowHandles() - else: - [h.setVisible(False) for h in self.selectionHandles] - - return super(Block, self).itemChange(change, value) - def hoverEnterEvent(self, event): - if not self.isSelected(): - self.repositionAndShowHandles() - super(Block, self).hoverEnterEvent(event) - def hoverLeaveEvent(self, event): - if not self.isSelected(): - [h.setVisible(False) for h in self.selectionHandles] - super(Block, self).hoverLeaveEvent(event) - def myDelete(self): - for p in self.inputs + self.outputs: - if p.connection: p.connection.myDelete() - self.scene().removeItem(self) - def repositionAndShowHandles(self): - r = self.rect() - self.selectionHandles[Position.TOP_LEFT].setPos(r.topLeft()) - self.selectionHandles[Position.TOP].setPos(r.center().x(), r.top()) - self.selectionHandles[Position.TOP_RIGHT].setPos(r.topRight()) - self.selectionHandles[Position.RIGHT].setPos(r.right(), r.center().y()) - self.selectionHandles[Position.BOTTOM_RIGHT].setPos(r.bottomRight()) - self.selectionHandles[Position.BOTTOM].setPos(r.center().x(), r.bottom()) - self.selectionHandles[Position.BOTTOM_LEFT].setPos(r.bottomLeft()) - self.selectionHandles[Position.LEFT].setPos(r.left(), r.center().y()) - for h in self.selectionHandles: - h.setVisible(True) - def sizerMoveEvent(self, handle, pos): - r = self.rect().translated(self.pos()) - if handle.position == Position.TOP_LEFT: r.setTopLeft(pos) - elif handle.position == Position.TOP: r.setTop(pos.y()) - elif handle.position == Position.TOP_RIGHT: r.setTopRight(pos) - elif handle.position == Position.RIGHT: r.setRight(pos.x()) - elif handle.position == Position.BOTTOM_RIGHT: r.setBottomRight(pos) - elif handle.position == Position.BOTTOM: r.setBottom(pos.y()) - elif handle.position == Position.BOTTOM_LEFT: r.setBottomLeft(pos) - elif handle.position == Position.LEFT: r.setLeft(pos.x()) - else: - print('invalid position') - self.setCenterAndSize(r.center(), r.size()) - self.repositionAndShowHandles() - def updateSize(self): - rect = self.rect() - h, w = rect.height(), rect.width() - self.buttonItemAddInput.setPos(0, h + 4) - self.buttonItemAddOutput.setPos(w+10, h+4) - for inp, y in zip(self.inputs, equalSpace(len(self.inputs), h)): - inp.setPos(0.0, y) - for outp, y in zip(self.outputs, equalSpace(len(self.outputs), h)): - outp.setPos(w, y) - def setCenterAndSize(self, center, size): - self.changeSize(size.width(), size.height()) - p = QPointF(size.width(), size.height()) - self.setPos(center - p / 2) - def changeSize(self, w, h): - minw = 150 - minh = 50 - h = minh if h < minh else h - w = minw if w < minw else w - self.setRect(0.0, 0.0, w, h) - rect = self.label.boundingRect() - self.label.setPos((w - rect.width()) / 2, (h - rect.height()) / 2) - self.updateSize() - -class CodeBlock(Block): - def __init__(self, name='Untitled', parent=None): - super(CodeBlock, self).__init__(name, parent) - self.code = '' - def setDict(self, d): - super(CodeBlock, self).setDict(d) - self.code = d['code'] - def getDict(self): - d = super(CodeBlock, self).getDict() - d['code'] = self.code - return d - def gencode(self): - c = ['def {0}():'.format(self.name)] - if self.code: - c += indent(self.code.split('\n')) - else: - c += indent(['pass']) - return c - -class DiagramBlock(Block): - def __init__(self, name='Untitled', parent=None): - super(DiagramBlock, self).__init__(name, parent) - self.subModel = DiagramScene() - self.subModel.containingBlock = self - def setDict(self, d): - self.subModel.Dict = d['submodel'] - def mouseDoubleClickEvent(self, event): - # descent into child diagram - #self.editParameters() - print('descent') - scene = self.scene() - if scene: - for view in scene.views(): - view.diagram = self.subModel - view.zoomAll() - -class DiagramScene(QGraphicsScene): - """ A diagram scene consisting of blocks and connections """ - structureChanged = pyqtSignal() - def __init__(self): - super(DiagramScene, self).__init__() - self.startedConnection = None - - blocks = property(lambda sel: [i for i in sel.items() if isinstance(i, Block)]) - connections = property(lambda sel: [i for i in sel.items() if type(i) is Connection]) - def addItem(self, item): - super(DiagramScene, self).addItem(item) - if isinstance(item, Block): - self.structureChanged.emit() - def removeItem(self, item): - super(DiagramScene, self).removeItem(item) - if isinstance(item, Block): - self.structureChanged.emit() - def setDict(self, d): - for block in d['blocks']: - b = Block() - self.addItem(b) - b.Dict = block - for con in d['connections']: - fromPort = self.findPort(con['fromBlock'], con['fromPort']) - toPort = self.findPort(con['toBlock'], con['toPort']) - self.addItem(Connection(fromPort, toPort)) - def getDict(self): - return {'blocks': [b.Dict for b in self.blocks], 'connections': [c.Dict for c in self.connections]} - Dict = property(getDict, setDict) - def gencode(self): - c = [] - for b in self.blocks: - c += b.gencode() - for b in self.blocks: - c.append('{0}()'.format(b.name)) - return c - def findPort(self, blockname, portname): - block = self.findBlock(blockname) - if block: - for port in block.inputs + block.outputs: - if port.name == portname: return port - def findBlock(self, blockname): - for block in self.blocks: - if block.name == blockname: return block - def uniqify(self, name): - blocknames = [item.name for item in self.blocks] - return uniqify(name, blocknames) - def mouseMoveEvent(self, event): - if self.startedConnection: - pos = event.scenePos() - self.startedConnection.setEndPos(pos) - super(DiagramScene, self).mouseMoveEvent(event) - def mouseReleaseEvent(self, event): - if self.startedConnection: - for item in self.items(event.scenePos()): - if type(item) is InputPort and item.connection == None: - self.startedConnection.setToPort(item) - self.startedConnection = None - return - self.startedConnection.myDelete() - self.startedConnection = None - super(DiagramScene, self).mouseReleaseEvent(event) - def startConnection(self, port): - self.startedConnection = Connection(port, None) - pos = port.scenePos() - self.startedConnection.setEndPos(pos) - self.addItem(self.startedConnection) - def deleteItems(self): - for item in list(self.selectedItems()): item.myDelete() -
--- a/python/hexfile.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -import os -import struct -import binascii - -DATA = 0 -EOF = 1 -EXTLINADR = 4 - -class HexFileException(Exception): - pass - -def parseHexLine(line): - """ Parses a hexfile line into three parts """ - line = line[1:] # Remove ':' - nums = bytes.fromhex(line) - bytecount = nums[0] - if len(nums) != bytecount + 5: - raise HexFileException('byte count field incorrect') - crc = sum(nums) - if (crc & 0xFF) != 0: - raise HexFileException('crc incorrect') - address = struct.unpack('>H', nums[1:3])[0] - typ = nums[3] - data = nums[4:-1] - return (address, typ, data) - -def makeHexLine(address, typ, data=bytes()): - bytecount = len(data) - nums = bytearray() - nums.append(bytecount) - nums.extend(struct.pack('>H', address)) - nums.append(typ) - nums.extend(data) - crc = sum(nums) - crc = ((~crc) + 1) & 0xFF - nums.append(crc) - line = ':' + binascii.hexlify(nums).decode('ascii') - return line - -def chunks(data, csize=16): - idx = 0 - while idx < len(data): - s = min(len(data) - idx, csize) - yield data[idx:idx+s] - idx += s - -def hexfields(f): - for line in f: - line = line.strip() # Strip spaces and newlines - if not line: - continue # Skip empty lines - if line[0] != ':': - continue # Skip lines that do not start with a ':' - yield parseHexLine(line) - - -class HexFile: - """ Represents an intel hexfile """ - def __init__(self): - self.regions = [] - self.startAddress = 0 - - def load(self, f): - endOfFile = False - ext = 0 - for address, typ, data in hexfields(f): - if endOfFile: - raise HexFileException('hexfile line after end of file record') - if typ == 0x0: # Data record - self.addRegion(address + ext, data) - elif typ == EXTLINADR: # Extended linear address record - ext = (struct.unpack('>H', data[0:2])[0]) << 16 - elif typ == EOF: # End of file record - if len(data) != 0: - raise HexFileException('end of file not empty') - endOfFile = True - elif typ == 0x5: # Start address record (where IP goes after loading) - self.startAddress = struct.unpack('>I', data[0:4])[0] - else: - raise HexFileException('record type {0} not implemented'.format(typ)) - - def __repr__(self): - size = sum(len(r.data) for r in self.regions) - return 'Hexfile containing {} bytes'.format(size) - - def dump(self): - print(self) - for r in self.regions: - print(r) - - def __eq__(self, other): - regions = self.regions - oregions = other.regions - if len(regions) != len(oregions): - return False - return all(rs == ro for rs, ro in zip(regions, oregions)) - - def addRegion(self, address, data): - r = HexFileRegion(address, data) - self.regions.append(r) - self.check() - - def check(self): - self.regions.sort(key=lambda r: r.address) - change = True - while change and len(self.regions) > 1: - change = False - for r1, r2 in zip(self.regions[:-1], self.regions[1:]): - if r1.EndAddress == r2.address: - r1.addData(r2.data) - self.regions.remove(r2) - change = True - elif r1.EndAddress > r2.address: - raise HexFileException('Overlapping regions') - - def merge(self, other): - for r in other.regions: - self.addRegion(r.address, r.data) - - def save(self, f): - def emit(address, typ, data=bytes()): - print(makeHexLine(address, typ, data), file=f) - for r in self.regions: - ext = r.address & 0xFFFF0000 - emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) - address = r.address - ext - for chunk in chunks(r.data): - if address >= 0x10000: - ext += 0x10000 - emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) - address -= 0x10000 - emit(address, DATA, chunk) - address += len(chunk) - emit(0, EOF) - -class HexFileRegion: - def __init__(self, address, data = bytes()): - self.address = address - self.data = data - - def __repr__(self): - return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data)) - - def __eq__(self, other): - return (self.address, self.data) == (other.address, other.data) - - def addData(self, d): - self.data = self.data + d - - @property - def EndAddress(self): - return self.address + len(self.data) - -
--- a/python/ide/ide.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/ide/ide.py Wed Nov 27 08:06:42 2013 +0100 @@ -10,11 +10,15 @@ from PyQt4.QtGui import * # Compiler imports: +p = os.path.join(os.path.dirname(__file__), '..') +# print(p) +sys.path.insert(0, p) +sys.path.insert(0, os.path.join(p, 'utils')) import ppci from astviewer import AstViewer from codeedit import CodeEdit from logview import LogView as BuildOutput -from disasm import Disassembly +#from disasm import Disassembly stutil = __import__('st-util') import c3 import zcc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/st-util.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,385 @@ +#!/usr/bin/python + +import sys +from PyQt4.QtCore import * +from PyQt4.QtGui import * +import stlink, devices, stm32, usb +from devices import Interface, Device +from hexedit import HexEdit + + +class InformationDialog(QDialog): + def __init__(self, parent): + super().__init__(parent) + self.setWindowTitle('Info') + fl = QFormLayout(self) + if parent.stl: + fl.addRow('ST link version:', QLabel(parent.stl.Version)) + fl.addRow('Chip id:', QLabel('0x{0:X}'.format(parent.stl.ChipId))) + fl.addRow('Current mode:', QLabel(parent.stl.CurrentModeString)) + fl.addRow('Status:', QLabel(parent.stl.StatusString)) + + +class RegisterModel(QAbstractTableModel): + def __init__(self): + super().__init__() + self.regCount = 15 + self.device = None + + def rowCount(self, parent): + if parent.isValid(): + return 0 + if self.device: + return 21 # TODO make variable + else: + return 0 + + def setDevice(self, dev): + self.device = dev + self.modelReset.emit() + + def columnCount(self, parent): + if parent.isValid(): + return 0 + return 2 + + def data(self, index, role): + if index.isValid(): + row, col = index.row(), index.column() + if role == Qt.DisplayRole: + if col == 0: + if row == 15: + return 'PC' + elif row == 14: + return 'LR' + elif row == 13: + return 'SP' + else: + return 'R{0}'.format(row) + elif col == 1: + v = self.device.iface.read_reg(row) + return '0x{0:X}'.format(v) + + def setData(self, index, value, role): + if index.isValid(): + row = index.row() + col = index.column() + if role == Qt.EditRole and col == 1: + value = int(value, 16) + self.device.iface.write_reg(row, value) + return True + return False + + def flags(self, index): + if index.isValid(): + row = index.row() + col = index.column() + if col == 1: + return super().flags(index) | Qt.ItemIsEditable + return super().flags(index) + + def refresh(self): + if self.device: + fromIndex = self.index(0, 1) + toIndex = self.index(21, 1) + self.dataChanged.emit(fromIndex, toIndex) + + +class RegisterView(QTableView): + def __init__(self): + super().__init__() + self.mdl = RegisterModel() + self.setModel(self.mdl) + + def refresh(self): + if self.mdl.device: + self.setEnabled(not self.mdl.device.Running) + self.mdl.refresh() + + +class MemoryView(QWidget): + BlockSize = 0x100 + def __init__(self): + super().__init__() + l = QVBoxLayout(self) + l2 = QHBoxLayout() + l2.addWidget(QLabel('Address')) + self.addressLine = QLineEdit() + self.addressLine.setInputMask('Hhhhhhhh') + l2.addWidget(self.addressLine) + upButton = QPushButton('up') + l2.addWidget(upButton) + upButton.clicked.connect(self.doUp) + downButton = QPushButton('down') + downButton.clicked.connect(self.doDown) + l2.addWidget(downButton) + l.addLayout(l2) + self.device = None + self.hexEdit = HexEdit() + self.Address = 0x8000000 + l.addWidget(self.hexEdit) + self.addressLine.returnPressed.connect(self.refresh) + + def refresh(self): + address = self.Address + if self.device: + data = self.device.iface.read_mem32(address, self.BlockSize) + else: + data = bytearray(self.BlockSize) + self.hexEdit.bv.Data = data + self.hexEdit.bv.Offset = address + + def getAddress(self): + txt = self.addressLine.text() + return int(txt, 16) + + def doUp(self): + self.Address -= self.BlockSize + + def doDown(self): + self.Address += self.BlockSize + + def setAddress(self, address): + self.addressLine.setText('{0:08X}'.format(address)) + self.refresh() + Address = property(getAddress, setAddress) + def setDevice(self, dev): + self.device = dev + self.Address = 0x8000000 + + +class DebugToolbar(QToolBar): + statusChange = pyqtSignal() + codePosition = pyqtSignal(int) + def __init__(self): + super().__init__() + self.device = None + # generate actions: + def genAction(name, callback): + a = QAction(name, self) + a.triggered.connect(callback) + self.addAction(a) + return a + self.stepAction = genAction('Step', self.doStep) + self.runAction = genAction('Run', self.doRun) + self.stopAction = genAction('Stop', self.doHalt) + self.resetAction = genAction('Reset', self.doReset) + self.enableTraceAction = genAction('Enable trace', self.doEnableTrace) + self.updateEnables() + def updateEnables(self): + if self.device: + self.resetAction.setEnabled(True) + self.enableTraceAction.setEnabled(True) + self.runAction.setEnabled(not self.device.Running) + self.stepAction.setEnabled(not self.device.Running) + self.stopAction.setEnabled(self.device.Running) + self.statusChange.emit() + if not self.device.Running: + PC = 15 + v = self.device.iface.read_reg(PC) + self.codePosition.emit(v) + else: + self.resetAction.setEnabled(False) + self.enableTraceAction.setEnabled(False) + self.runAction.setEnabled(False) + self.stepAction.setEnabled(False) + self.stopAction.setEnabled(False) + def doStep(self): + self.device.iface.step() + self.updateEnables() + def doReset(self): + self.device.iface.reset() + self.updateEnables() + def doRun(self): + self.device.iface.run() + self.updateEnables() + def doHalt(self): + self.device.iface.halt() + self.updateEnables() + def doEnableTrace(self): + self.device.iface.traceEnable() + self.updateEnables() + def setDevice(self, dev): + self.device = dev + self.updateEnables() + + +class FlashTool(QWidget): + def __init__(self): + super().__init__() + # TODO! + + +class DeviceTreeModel(QAbstractItemModel): + def __init__(self): + super().__init__() + self.chipPixmap = QPixmap('icons/chip.png').scaled(32, 32) + self.hardwarePixmap = QPixmap('icons/hardware.png').scaled(32, 32) + self.refresh() + def refresh(self): + """ Check all usb interfaces for interfaces """ + self.interfaces = devices.createInterfaces() + self.devices = [] + self.modelReset.emit() + def addDevice(self, device): + if device.iface in [lambda d: d.iface for d in self.devices]: + print('device already open') + return + self.devices.append(device) + self.modelReset.emit() + def index(self, row, column, parent): + if parent.isValid(): + ip = parent.internalPointer() + if isinstance(ip, Interface): + devs = [d for d in self.devices if d.iface is ip] + return self.createIndex(row, column, devs[row]) + else: + iface = self.interfaces[row] + return self.createIndex(row, column, iface) + return idx + def parent(self, index): + if index.isValid(): + ip = index.internalPointer() + if isinstance(ip, Interface): + return QModelIndex() + elif isinstance(ip, Device): + iface = ip.iface + row = self.interfaces.index(iface) + return self.createIndex(row, 0, iface) + return QModelIndex() + def rowCount(self, parent): + if parent.isValid(): + # non-root level: + ip = parent.internalPointer() + if isinstance(ip, Interface): + devs = [d for d in self.devices if d.iface is ip] + return len(devs) + else: + # root level: + return len(self.interfaces) + return 0 + def columnCount(self, parent): + return 1 + def data(self, index, role): + if index.isValid(): + ip = index.internalPointer() + if role == Qt.DisplayRole: + return str(ip) + elif role == Qt.DecorationRole: + if isinstance(ip, Interface): + return self.hardwarePixmap + if isinstance(ip, Device): + return self.chipPixmap + +class DeviceExplorer(QTreeView): + """ Lists all interfaces plugged in and allows selection """ + deviceSelected = pyqtSignal(Device) + def __init__(self): + super().__init__() + self.mdl = DeviceTreeModel() + self.setModel(self.mdl) + self.activated.connect(self.openItem) + self.header().close() + self.customContextMenuRequested.connect(self.openMenu) + self.setContextMenuPolicy(Qt.CustomContextMenu) + def openItem(self, idx): + if idx.isValid(): + ip = idx.internalPointer() + if isinstance(ip, Interface): + if not ip.IsOpen: + try: + ip.open() + except usb.UsbError as e: + QMessageBox.critical(self, "Error", 'Error opening interface: "{0}"'.format(e)) + else: + # Try to get a device: + self.mdl.addDevice(ip.createDevice()) + if isinstance(ip, Device): + self.deviceSelected.emit(ip) + def openMenu(self, pt): + idx = self.indexAt(pt) + menu = QMenu() + menu.addAction('Refresh', self.mdl.refresh) + if idx.isValid(): + ip = idx.internalPointer() + if isinstance(ip, Interface): + if ip.IsOpen: + def closeInterface(): + self.mdl.closeInterface(ip) + menu.addAction('Close', closeInterface) + else: + def openInterface(): + ip.open() + # Try to get a device: + self.mdl.addDevice(ip.createDevice()) + menu.addAction('Open', openInterface) + elif isinstance(ip, Device): + def selectDevice(): + self.deviceSelected.emit(ip) + menu.addAction('Select', selectDevice) + menu.exec(self.mapToGlobal(pt)) + + +class StUtil(QMainWindow): + connected = pyqtSignal(bool) + def __init__(self): + super().__init__() + self.stl = None + def buildAction(name, callback, shortcut=None): + a = QAction(name, self) + a.triggered.connect(callback) + if shortcut: + a.setShortcut(shortcut) + return a + mb = self.menuBar() + fileMenu = mb.addMenu("File") + self.connectAction = buildAction('Connect', self.connect) + fileMenu.addAction(self.connectAction) + self.disconnectAction = buildAction('Disconnect', self.disconnect) + fileMenu.addAction(self.disconnectAction) + + self.miscMenu = mb.addMenu("Misc") + infoAction = buildAction('Info', self.info) + self.miscMenu.addAction(infoAction) + + sb = self.statusBar() + + devexplr = DeviceExplorer() + self.setCentralWidget(devexplr) + devexplr.deviceSelected.connect(self.handleDeviceSelected) + + self.connected.connect(self.handleConnectedChange) + self.connected.emit(False) + def handleDeviceSelected(self, dev): + self.dev = dev + self.handleConnectedChange(True) + def handleConnectedChange(self, state): + self.miscMenu.setEnabled(state) + self.connectAction.setEnabled(not state) + self.disconnectAction.setEnabled(state) + msg = 'Connected!' if state else 'Disconnected!' + self.statusBar().showMessage(msg) + def info(self): + infoDialog = InformationDialog(self) + infoDialog.exec() + def connect(self): + try: + self.stl = stlink.STLink() + self.stl.open() + except (stlink.STLinkException, usb.UsbError) as e: + QMessageBox.warning(self, "Error", str(e)) + self.stl = None + if self.stl: + self.connected.emit(True) + def disconnect(self): + if self.stl: + self.stl.close() + self.connected.emit(False) + self.stl = None + +if __name__ == '__main__': + app = QApplication(sys.argv) + stu = StUtil() + stu.show() + app.exec() +
--- a/python/ir.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/ir.py Wed Nov 27 08:06:42 2013 +0100 @@ -278,12 +278,15 @@ """ Convenience call """ return Binop(a, '+', b) + def Sub(a, b): return Binop(a, '-', b) + def Mul(a, b): return Binop(a, '*', b) + def Div(a, b): return Binop(a, '/', b)
--- a/python/irmach.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/irmach.py Wed Nov 27 08:06:42 2013 +0100 @@ -67,5 +67,3 @@ p = '%l{}'.format(i) x = x.replace(p, str(j)) return x - -
--- a/python/lsusb.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -#!/usr/bin/python - -from usb import UsbContext - -# try to read usb.ids: -vids = {} -pids = {} -try: - with open('usb.ids', 'r', errors='ignore') as f: - vid = 0 - for l in f: - if l.startswith('#') or not l.strip(): - continue - if l.startswith('\t\t'): - print('iface:', l) - elif l.startswith('\t'): - print('product', l) - pid = int(l[1:5], 16) - print('product', hex(pid), l) - else: - print('vendor', l) - vid = int(l[0:4], 16) - print('vendor', hex(vid), l) - -except IOError as e: - print("Error loading usb id's: {0}".format(e)) - -context = UsbContext() -for d in context.DeviceList: - print(d) -
--- a/python/makeinitrd.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -#!/usr/bin/python - -# Script for generation of an initial ramdisk that contains -# the first programs to run. - -import struct -import sys - -if len(sys.argv) < 3: - print('Usage: {0} output file1 [file2] ...'.format(sys.argv[0])) - sys.exit(1) - -outputfilename = sys.argv[1] -inputFileNames = sys.argv[2:] - -with open(outputfilename, 'wb') as outputFile: - # Amount of files: - outputFile.write(struct.pack('<I', 0x1337babe)) - outputFile.write(struct.pack('<I', len(inputFileNames))) - for inputFileName in inputFileNames: - # Magic: - outputFile.write(struct.pack('<I', 0xcafebabe)) - - # Filename: - fn = inputFileName.encode('ascii') - outputFile.write(struct.pack('<I', len(fn))) - outputFile.write(fn) - - # Data: - with open(inputFileName, 'rb') as inputFile: - data = inputFile.read() - outputFile.write(struct.pack('<I', len(data))) - outputFile.write(data) -
--- a/python/mem2reg.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/mem2reg.py Wed Nov 27 08:06:42 2013 +0100 @@ -7,6 +7,7 @@ assert type(allocinst) is Alloc return all(type(use) in [Load, Store] for use in allocinst.value.used_by) + class Mem2RegPromotor(FunctionPass): def promoteSingleBlock(self, ai): v = ai.value
--- a/python/other/bouncing_cube.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/other/bouncing_cube.py Wed Nov 27 08:06:42 2013 +0100 @@ -11,7 +11,6 @@ import numpy as np import time import scipy.integrate -#import pyopencl """ Test script that lets a dice bounce. @@ -21,139 +20,142 @@ http://www.20sim.com """ + +# OpenGL drawing madness: def drawCube(w): - glBegin(GL_QUADS) # Start Drawing The Cube - glColor3f(0.0,1.0,0.0) # Set The Color To Blue - glVertex3f( w, w,-w) # Top Right Of The Quad (Top) - glVertex3f(-w, w,-w) # Top Left Of The Quad (Top) - glVertex3f(-w, w, w) # Bottom Left Of The Quad (Top) - glVertex3f( w, w, w) # Bottom Right Of The Quad (Top) + glBegin(GL_QUADS) # Start Drawing The Cube + glColor3f(0.0,1.0,0.0) # Set The Color To Blue + glVertex3f( w, w,-w) # Top Right Of The Quad (Top) + glVertex3f(-w, w,-w) # Top Left Of The Quad (Top) + glVertex3f(-w, w, w) # Bottom Left Of The Quad (Top) + glVertex3f( w, w, w) # Bottom Right Of The Quad (Top) - glColor3f(1.0,0.5,0.0) # Set The Color To Orange - glVertex3f( w,-w, w) # Top Right Of The Quad (Bottom) - glVertex3f(-w,-w, w) # Top Left Of The Quad (Bottom) - glVertex3f(-w,-w,-w) # Bottom Left Of The Quad (Bottom) - glVertex3f( w,-w,-w) # Bottom Right Of The Quad (Bottom) + glColor3f(1.0,0.5,0.0) # Set The Color To Orange + glVertex3f( w,-w, w) # Top Right Of The Quad (Bottom) + glVertex3f(-w,-w, w) # Top Left Of The Quad (Bottom) + glVertex3f(-w,-w,-w) # Bottom Left Of The Quad (Bottom) + glVertex3f( w,-w,-w) # Bottom Right Of The Quad (Bottom) - glColor3f(1.0,0.0,0.0) # Set The Color To Red - glVertex3f( w, w, w) # Top Right Of The Quad (Front) - glVertex3f(-w, w, w) # Top Left Of The Quad (Front) - glVertex3f(-w,-w, w) # Bottom Left Of The Quad (Front) - glVertex3f( w,-w, w) # Bottom Right Of The Quad (Front) + glColor3f(1.0,0.0,0.0) # Set The Color To Red + glVertex3f( w, w, w) # Top Right Of The Quad (Front) + glVertex3f(-w, w, w) # Top Left Of The Quad (Front) + glVertex3f(-w,-w, w) # Bottom Left Of The Quad (Front) + glVertex3f( w,-w, w) # Bottom Right Of The Quad (Front) - glColor3f(1.0,1.0,0.0) # Set The Color To Yellow - glVertex3f( w,-w,-w) # Bottom Left Of The Quad (Back) - glVertex3f(-w,-w,-w) # Bottom Right Of The Quad (Back) - glVertex3f(-w, w,-w) # Top Right Of The Quad (Back) - glVertex3f( w, w,-w) # Top Left Of The Quad (Back) + glColor3f(1.0,1.0,0.0) # Set The Color To Yellow + glVertex3f( w,-w,-w) # Bottom Left Of The Quad (Back) + glVertex3f(-w,-w,-w) # Bottom Right Of The Quad (Back) + glVertex3f(-w, w,-w) # Top Right Of The Quad (Back) + glVertex3f( w, w,-w) # Top Left Of The Quad (Back) - glColor3f(0.0,0.0,1.0) # Set The Color To Blue - glVertex3f(-w, w, w) # Top Right Of The Quad (Left) - glVertex3f(-w, w,-w) # Top Left Of The Quad (Left) - glVertex3f(-w,-w,-w) # Bottom Left Of The Quad (Left) - glVertex3f(-w,-w, w) # Bottom Right Of The Quad (Left) + glColor3f(0.0,0.0,1.0) # Set The Color To Blue + glVertex3f(-w, w, w) # Top Right Of The Quad (Left) + glVertex3f(-w, w,-w) # Top Left Of The Quad (Left) + glVertex3f(-w,-w,-w) # Bottom Left Of The Quad (Left) + glVertex3f(-w,-w, w) # Bottom Right Of The Quad (Left) - glColor3f(1.0,0.0,1.0) # Set The Color To Violet - glVertex3f( w, w,-w) # Top Right Of The Quad (Right) - glVertex3f( w, w, w) # Top Left Of The Quad (Right) - glVertex3f( w,-w, w) # Bottom Left Of The Quad (Right) - glVertex3f( w,-w,-w) # Bottom Right Of The Quad (Right) - glEnd() # Done Drawing The Quad + glColor3f(1.0,0.0,1.0) # Set The Color To Violet + glVertex3f( w, w,-w) # Top Right Of The Quad (Right) + glVertex3f( w, w, w) # Top Left Of The Quad (Right) + glVertex3f( w,-w, w) # Bottom Left Of The Quad (Right) + glVertex3f( w,-w,-w) # Bottom Right Of The Quad (Right) + glEnd() # Done Drawing The Quad def drawFloor(w, h): - glBegin(GL_QUADS) # Start Drawing The Cube - - glColor3f(1.0,0.5,0.0) # Set The Color To Orange - glVertex3f( w,-w,h)# Top Right Of The Quad (Bottom) - glVertex3f(-w,-w,h)# Top Left Of The Quad (Bottom) - glVertex3f(-w,w,h)# Bottom Left Of The Quad (Bottom) - glVertex3f( w,w,h)# Bottom Right Of The Quad (Bottom) - glEnd() # Done Drawing The Quad + glBegin(GL_QUADS) # Start Drawing The Cube + glColor3f(1.0,0.5,0.0) # Set The Color To Orange + glVertex3f( w,-w,h)# Top Right Of The Quad (Bottom) + glVertex3f(-w,-w,h)# Top Left Of The Quad (Bottom) + glVertex3f(-w,w,h)# Bottom Left Of The Quad (Bottom) + glVertex3f( w,w,h)# Bottom Right Of The Quad (Bottom) + glEnd() # Done Drawing The Quad def drawAxis(): - glLineWidth(0.5) - glBegin(GL_LINES) - glColor3f(1.0, 0.0, 0.0) - glVertex3f(0,0,0) - glVertex3f(1,0,0) - glColor3f(0.0, 1.0, 0.0) - glVertex3f(0,0,0) - glVertex3f(0,1,0) - glColor3f(0.0, 0.0, 1.0) - glVertex3f(0,0,0) - glVertex3f(0,0,1) - glEnd() + glLineWidth(0.5) + glBegin(GL_LINES) + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0,0,0) + glVertex3f(1,0,0) + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0,0,0) + glVertex3f(0,1,0) + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0,0,0) + glVertex3f(0,0,1) + glEnd() +# Math helper functions: + def cross(A, B): - a = A.A1 - b = B.A1 - return mat(np.cross(a, b)).T + a = A.A1 + b = B.A1 + return mat(np.cross(a, b)).T def skew(X): - Y = mat(zeros( (3, 3) )) - a,b,c = X.A1 - Y[0,1] = -c - Y[0,2] = b - Y[1,0] = c - Y[1,2] = -a - Y[2,0] = -b - Y[2,1] = a - return Y + Y = mat(zeros( (3, 3) )) + a, b, c = X.A1 + Y[0,1] = -c + Y[0,2] = b + Y[1,0] = c + Y[1,2] = -a + Y[2,0] = -b + Y[2,1] = a + return Y def adjoint(T): - W = T[0:3, 0] - V = T[3:6, 0] - a = mat(zeros( (6,6) ) ) - a[0:3, 0:3] = skew(W) - a[3:6, 0:3] = skew(V) - a[3:6, 3:6] = skew(W) - return a + W = T[0:3, 0] + V = T[3:6, 0] + a = mat(zeros( (6, 6) ) ) + a[0:3, 0:3] = skew(W) + a[3:6, 0:3] = skew(V) + a[3:6, 3:6] = skew(W) + return a def Adjoint(H): - R = H[0:3, 0:3] - P = H[0:3, 3] - a = mat(zeros( (6,6) ) ) - a[0:3, 0:3] = R - a[3:6, 3:6] = R - a[3:6, 0:3] = skew(P) * R - return a + R = H[0:3, 0:3] + P = H[0:3, 3] + a = mat(zeros( (6, 6) ) ) + a[0:3, 0:3] = R + a[3:6, 3:6] = R + a[3:6, 0:3] = skew(P) * R + return a def quatToR(q): - x, y, z, w = q.A1 - r = mat(eye(3)) - r[0,0] = 1 - (2*y**2+2*z**2) - r[0,1] = 2*x*y+2*z*w - r[0,2] = 2*x*z - 2*y*w - r[1,0] = 2*x*y-2*z*w - r[1,1] = 1 - (2*x**2 + 2*z**2) - r[1,2] = 2*y*z + 2*x*w - r[2,0] = 2*x*z+2*y*w - r[2,1] = 2*y*z - 2*x*w - r[2,2] = 1 - (2*x**2+2*y**2) - return r + x, y, z, w = q.A1 + r = mat(eye(3)) + r[0,0] = 1 - (2*y**2+2*z**2) + r[0,1] = 2*x*y+2*z*w + r[0,2] = 2*x*z - 2*y*w + r[1,0] = 2*x*y-2*z*w + r[1,1] = 1 - (2*x**2 + 2*z**2) + r[1,2] = 2*y*z + 2*x*w + r[2,0] = 2*x*z+2*y*w + r[2,1] = 2*y*z - 2*x*w + r[2,2] = 1 - (2*x**2+2*y**2) + return r def rotateAbout(axis, angle): - ax, ay, az = (axis/norm(axis)).A1 - qx = ax*sin(angle/2.0) - qy = ay*sin(angle/2.0) - qz = az*sin(angle/2.0) - qw = cos(angle/2.0) - q = mat(array([qx,qy,qz,qw])).T - return q + ax, ay, az = (axis/norm(axis)).A1 + qx = ax*sin(angle/2.0) + qy = ay*sin(angle/2.0) + qz = az*sin(angle/2.0) + qw = cos(angle/2.0) + q = mat(array([qx,qy,qz,qw])).T + return q def normalizeQuaternion(quat): - x,y,z,w = quat.A1 - magnitude = sqrt(x*x + y*y + z*z + w*w) - x = x / magnitude - y = y / magnitude - z = z / magnitude - w = w / magnitude - quat[0, 0] = x - quat[1, 0] = y - quat[2, 0] = z - quat[3, 0] = w - return quat + x,y,z,w = quat.A1 + magnitude = sqrt(x*x + y*y + z*z + w*w) + x = x / magnitude + y = y / magnitude + z = z / magnitude + w = w / magnitude + quat[0, 0] = x + quat[1, 0] = y + quat[2, 0] = z + quat[3, 0] = w + return quat def VTo4x4(V): v1, v2, v3 = V.A1 @@ -163,211 +165,256 @@ [-v2, v1, 0.0, -v3], \ [v1, v2, v3, 0.0] ])) -def homogeneous(R,p): +def homogeneous(R, p): + """ Create a H matrix from rotation and position """ H = mat(eye(4)) H[0:3, 0:3] = R H[0:3, 3] = p return H -def rateOfChange(states, thetime, parameters): - quat = states[0:4, 0] # Orientation (4) - pos = states[4:7, 0] # Position (3) - P = states[7:13, 0] # Momentum (6) - massI, gravity = parameters - # Rigid body parts: - # Forward Kinematic chain: - H = homogeneous(quatToR(quat), pos) # Forward kinematics - AdjX2 = mat(eye(6)) # The connectionpoint in the real world - adjAdjX2_1 = adjoint(AdjX2[0:6,0]) - adjAdjX2_2 = adjoint(AdjX2[0:6,1]) - adjAdjX2_3 = adjoint(AdjX2[0:6,2]) - adjAdjX2_4 = adjoint(AdjX2[0:6,3]) - adjAdjX2_5 = adjoint(AdjX2[0:6,4]) - adjAdjX2_6 = adjoint(AdjX2[0:6,5]) - AdjInv2 = Adjoint(H.I) - M2 = AdjInv2.T * (massI * AdjInv2) # Transfor mass to base frame - MassMatrix = M2 - - wrenchGrav2 = mat( zeros((1,6)) ) - wrenchGrav2[0, 0:3] = -cross(gravity, pos).T - wrenchGrav2[0, 3:6] = gravity.T - - Bk = mat( zeros( (6,6) )) - Bk[0:3, 0:3] = skew(P[0:3, 0]) - Bk[3:6, 0:3] = skew(P[3:6, 0]) - Bk[0:3, 3:6] = skew(P[3:6, 0]) - - # TODO: do this a cholesky: - v = np.linalg.solve(MassMatrix, P) # Matrix inverse like thingy ! - - T2_00 = v # Calculate the relative twist! - TM2 = T2_00.T * M2 - twistExternal = T2_00 # Twist van het blokje - TMSum2 = TM2 - - PDotBodies = mat( zeros( (6,1)) ) - PDotBodies[0,0] = TMSum2 * (adjAdjX2_1 * T2_00) - PDotBodies[1,0] = TMSum2 * (adjAdjX2_2 * T2_00) - PDotBodies[2,0] = TMSum2 * (adjAdjX2_3 * T2_00) - PDotBodies[3,0] = TMSum2 * (adjAdjX2_4 * T2_00) - PDotBodies[4,0] = TMSum2 * (adjAdjX2_5 * T2_00) - PDotBodies[5,0] = TMSum2 * (adjAdjX2_6 * T2_00) - - PDot = -PDotBodies - Bk * v - PDot += wrenchGrav2.T - - ##### Contact wrench part: - HB_W = H # Is H-matrix van het blokje - WrenchB = mat(zeros( (1,6) )) - for px in [-0.5, 0.5]: - for py in [-0.5, 0.5]: - for pz in [-0.5, 0.5]: - HB1_B = homogeneous(mat(eye(3)), mat([px,py,pz]).T) - HB1_W = HB_W * HB1_B - HW1_W = homogeneous(mat(eye(3)), HB1_W[0:3,3]) - HW_W1 = HW1_W.I - HB_W1 = HW_W1 * HB_W - - AdjHB_W1 = Adjoint(HB_W1) - TB_W1_W1 = AdjHB_W1 * twistExternal - z = HB1_W[2, 3] - vx, vy, vz = TB_W1_W1[3:6, 0].A1 - if z < 0: - # Contact forces: - Fx = -50.0*vx - Fy = -50.0*vy - Fz = -z*50000.0 - else: - Fx = 0.0 - Fy = 0.0 - Fz = 0.0 - # TODO: reflect impulse - WrenchW1 = mat([0,0,0,0,0,Fz]) - # Transform it back: - WrenchB += (AdjHB_W1.T * WrenchW1.T).T - ##### End of contact wrench - - PDot += (WrenchB * AdjInv2).T - - # Position and orientation rates: - QOmega = VTo4x4(v[0:3, 0]) - quatDot = 0.5 * QOmega * quat - vel = v[3:6, 0] - posDot = skew(v[0:3]) * pos + vel - # The rate vector: - rates = mat(zeros( (13,1) )) - rates[0:4, 0] = quatDot - rates[4:7, 0] = posDot - rates[7:13, 0] = PDot - return rates - -def fWrapper(y, t, parameters): - y = mat(y).T - dy = rateOfChange(y, t, parameters) - return dy.T.A1 - -def SCIPY(endtime, dt, state, parameters): - times = np.arange(0.0, endtime, dt) - y0 = state.T.A1 - res = scipy.integrate.odeint(fWrapper, y0, times, args=(parameters,)) - states = [] - res = res.T - r,c = res.shape - for ci in range(0,c): - states.append(mat(res[:,ci]).T) - return states - -def RK4(endtime, dt, state, parameters): - t = 0.0 - states = [] - while t < endtime: - newstate = mat (zeros( state.shape )) # Create a new object - - #### Runge Kutta integration: - k1 = rateOfChange(state, t, parameters) - k2 = rateOfChange(state + 0.5*dt*k1, t, parameters) - k3 = rateOfChange(state + 0.5*dt*k1, t, parameters) - k4 = rateOfChange(state + dt*k3, t, parameters) - newstate = state + (dt/6.0)*(k1+2*k2+2*k3+k4) - - # Normalize quat: - newstate[0:4, 0] = normalizeQuaternion(newstate[0:4, 0]) - states.append(newstate) - - state = newstate - - t += dt - print(state[6,0], t, ' ', (t/endtime)*100.0, '%') - return states +class Simulation: + def simulate(self, endtime, dt): + """ Evaluate the state of the system over a given time """ + state = self.initial() + times = np.arange(0.0, endtime, dt) + y0 = state.T.A1 + def fWrapper(y, t): + y = mat(y).T + dy = self.rateOfChange(y, t) + return dy.T.A1 + res = scipy.integrate.odeint(fWrapper, y0, times) + states = [] + res = res.T + r,c = res.shape + for ci in range(0,c): + states.append(mat(res[:,ci]).T) + self.result = states + return states -def simulate(endtime, dt): - PInitial = mat( zeros((6,1)) ) - posInitial = mat(array([-1.2, -1.3, 2.8])).T - quatInitial = rotateAbout(mat(array([0.2, 1.0, 0.4])).T, 0.5) - # Parameters: - gravity = mat( array([0,0,-9.81]) ).T - massI = mat(eye(6)) * 1.01 # Mass matrix - parameters = (massI, gravity) +class BouncingCube(Simulation): + """ Simulation of a bouncing cube """ + def __init__(self): + # Parameters: + self.gravity = mat( array([0,0,-9.81]) ).T + self.massI = mat(eye(6)) * 1.01 # Mass matrix + + def initial(self): + """ Return initial pose """ + PInitial = mat( zeros((6, 1)) ) + posInitial = mat(array([-1.2, -1.3, 2.8])).T + quatInitial = rotateAbout(mat(array([0.2, 1.0, 0.4])).T, 0.5) + + # The state vector! + state = mat(zeros( (13,1) )) + state[0:4, 0] = quatInitial + state[4:7, 0] = posInitial + state[7:13, 0] = PInitial + return state + + def rateOfChange(self, states, thetime): + """ Calculates rate of change given the current states. """ + quat = states[0:4, 0] # Orientation (4) + pos = states[4:7, 0] # Position (3) + P = states[7:13, 0] # Momentum (6) + massI, gravity = self.massI, self.gravity + # Rigid body parts: + # Forward Kinematic chain: + H = homogeneous(quatToR(quat), pos) # Forward kinematics + + AdjX2 = mat(eye(6)) # The connectionpoint in the real world + adjAdjX2_1 = adjoint(AdjX2[0:6,0]) + adjAdjX2_2 = adjoint(AdjX2[0:6,1]) + adjAdjX2_3 = adjoint(AdjX2[0:6,2]) + adjAdjX2_4 = adjoint(AdjX2[0:6,3]) + adjAdjX2_5 = adjoint(AdjX2[0:6,4]) + adjAdjX2_6 = adjoint(AdjX2[0:6,5]) + AdjInv2 = Adjoint(H.I) + M2 = AdjInv2.T * (massI * AdjInv2) # Transfor mass to base frame + MassMatrix = M2 + + wrenchGrav2 = mat( zeros((1,6)) ) + wrenchGrav2[0, 0:3] = -cross(gravity, pos).T + wrenchGrav2[0, 3:6] = gravity.T + + Bk = mat( zeros( (6,6) )) + Bk[0:3, 0:3] = skew(P[0:3, 0]) + Bk[3:6, 0:3] = skew(P[3:6, 0]) + Bk[0:3, 3:6] = skew(P[3:6, 0]) + + # TODO: do this a cholesky: + v = np.linalg.solve(MassMatrix, P) # Matrix inverse like thingy ! + + T2_00 = v # Calculate the relative twist! + TM2 = T2_00.T * M2 + twistExternal = T2_00 # Twist van het blokje + TMSum2 = TM2 - # The state vector! - state = mat(zeros( (13,1) )) - state[0:4, 0] = quatInitial - state[4:7, 0] = posInitial - state[7:13, 0] = PInitial + PDotBodies = mat( zeros( (6,1)) ) + PDotBodies[0,0] = TMSum2 * (adjAdjX2_1 * T2_00) + PDotBodies[1,0] = TMSum2 * (adjAdjX2_2 * T2_00) + PDotBodies[2,0] = TMSum2 * (adjAdjX2_3 * T2_00) + PDotBodies[3,0] = TMSum2 * (adjAdjX2_4 * T2_00) + PDotBodies[4,0] = TMSum2 * (adjAdjX2_5 * T2_00) + PDotBodies[5,0] = TMSum2 * (adjAdjX2_6 * T2_00) + + PDot = -PDotBodies - Bk * v + PDot += wrenchGrav2.T + + ##### Contact wrench part: + HB_W = H # Is H-matrix van het blokje + WrenchB = mat(zeros( (1,6) )) + for px in [-0.5, 0.5]: + for py in [-0.5, 0.5]: + for pz in [-0.5, 0.5]: + HB1_B = homogeneous(mat(eye(3)), mat([px,py,pz]).T) + HB1_W = HB_W * HB1_B + HW1_W = homogeneous(mat(eye(3)), HB1_W[0:3,3]) + HW_W1 = HW1_W.I + HB_W1 = HW_W1 * HB_W + + AdjHB_W1 = Adjoint(HB_W1) + TB_W1_W1 = AdjHB_W1 * twistExternal + z = HB1_W[2, 3] + vx, vy, vz = TB_W1_W1[3:6, 0].A1 + if True: + # Contact forces: + Fx = 0 #np.exp(-5.0*vx) + Fy = 0 # np.exp(-5.0*vy) + Fz = np.exp(-z*10.0) + else: + Fx = 0.0 + Fy = 0.0 + Fz = 0.0 + # TODO: reflect impulse + WrenchW1 = mat([0,0,0,0,0,Fz]) + # Transform it back: + WrenchB += (AdjHB_W1.T * WrenchW1.T).T + ##### End of contact wrench + + PDot += (WrenchB * AdjInv2).T + + # Position and orientation rates: + QOmega = VTo4x4(v[0:3, 0]) + quatDot = 0.5 * QOmega * quat + vel = v[3:6, 0] + posDot = skew(v[0:3]) * pos + vel + # The rate vector: + rates = mat(zeros( (13,1) )) + rates[0:4, 0] = quatDot + rates[4:7, 0] = posDot + rates[7:13, 0] = PDot + return rates - return SCIPY(endtime, dt, state, parameters) + def draw(self, state): + Dicequat = state[0:4, 0] + Dicepos = state[4:7, 0] + + x, y, z = Dicepos.A1 + R = quatToR(Dicequat) + + glTranslatef(x, y, z) + # Trick to rotate the openGL matrix: + r = R.A1 + rotR = (r[0], r[3], r[6], 0.0, + r[1], r[4], r[7], 0.0, + r[2], r[5], r[8], 0.0, + 0.0, 0.0, 0.0, 1.0) + glMultMatrixd(rotR) + + drawCube(0.6) + + +class RollingPendulum(Simulation): + """ A 2D pendulum with a rolling contact. """ + def __init__(self): + self.R = 0.01 + self.L = 1 + self.M = 1 + self.g = 9.81 + + def initial(self): + i = mat(zeros((2,1))) + i[0, 0] = + return i + + def rateOfChange(self, states, thetime): + phi, omega = states[0:2, 0] + rates = mat(zeros((2,1))) + return rates + + def draw(self, state): + pass + #drawCube(0.6) + + +class WobbelingWheel(Simulation): + """ A wheel pushed sideways over a surface """ + def __init__(self): + self.r1 = 0.5 + self.r2 = 0.05 + + def initial(self): + i = mat(zeros((5,1))) + return i + + def rateOfChange(self, states, thetime): + x, y = states[0:2, 0] + rates = mat(zeros((5,1))) + return rates + + def draw(self, state): + pass + #drawCube(0.6) + class W(QGLWidget): - time = 0.0 - index = 0 - def __init__(self, states, dt, parent=None): - super(W, self).__init__(parent) - self.firstRun = True - self.savePNGS = False - self.dt = dt - self.resize(500,500) - self.states = states - self.UP() - t = QTimer(self) - t.timeout.connect(self.UP) - t.start(self.dt*1000.0) + time = 0.0 + index = 0 + def __init__(self, sim): + super().__init__() + self.firstRun = True + self.savePNGS = False + self.index = 0 + self.sim = sim + self.resize(500,500) + self.UP() + t = QTimer(self) + t.timeout.connect(self.UP) + t.start(40) - def UP(self): - self.time += self.dt - if self.states: - state = self.states[self.index] - self.Dicequat = state[0:4, 0] - self.Dicepos = state[4:7, 0] - self.index += 1 - if self.index == len(self.states): - self.index = 0 - self.firstRun = False - # Paint: - self.update() - if self.firstRun: - # Create png images for the movie: - if self.savePNGS: - pm = self.renderPixmap() - pm.save('image'+str(self.index)+'.png') + def UP(self): + if self.sim.result: + if self.index + 1 < len(self.sim.result): + self.index += 1 + else: + self.index = 0 + # Paint: + self.update() + + if self.firstRun: + # Create png images for the movie: + if self.savePNGS: + pm = self.renderPixmap() + pm.save('image'+str(self.index)+'.png') - def initializeGL(self): + def initializeGL(self): glClearColor(0.0, 0.5, 0.0, 1.0) glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LESS) glShadeModel(GL_SMOOTH) - def resizeGL(self,w,h): + + def resizeGL(self,w,h): glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45.0, float(w)/float(h), 0.1, 100.0) glMatrixMode(GL_MODELVIEW) - def paintGL(self): + + def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Clear buffers glLoadIdentity() # Reset The View - - glLoadIdentity() glTranslatef(0.0,-2.0,-10.0) # Move Left And Into The Screen glRotatef(-90.0, 1.0, 0.0, 0.0) drawFloor(2.0, 0.0) @@ -375,32 +422,22 @@ self.renderText(1.0, 0.0, 0.0, 'X') self.renderText(0.0, 1.0, 0.0, 'Y') self.renderText(0.0, 0.0, 1.0, 'Z') - self.renderText(0.0,0.0,1.2,str(self.time)) + if self.sim.result: + self.sim.draw(self.sim.result[self.index]) - x,y,z = self.Dicepos.A1 - R = quatToR(self.Dicequat) - glTranslatef(x, y, z) - # Trick to rotate the openGL matrix: - r = R.A1 - rotR = (r[0], r[3], r[6], 0.0, - r[1], r[4], r[7], 0.0, - r[2], r[5], r[8], 0.0, - 0.0, 0.0, 0.0, 1.0) - glMultMatrixd(rotR) - - drawCube(0.6) - -et = 20.0 +et = 1.5 dt = 0.04 +# sim = BouncingCube() +sim = WobbelingWheel() print('starting integration... endtime =', et, ' stepsize =', dt) t0 = time.time() -states = simulate(et, dt) +states = sim.simulate(et, dt) t1 = time.time() -print('That was heavy, it took me ', t1-t0, ' seconds!') +print('That was heavy, it took me ', t1 -t0, ' seconds!') app = QApplication(sys.argv) -w = W(states, dt) +w = W(sim) w.show() sys.exit(app.exec_())
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/other/diagramitems.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,437 @@ +""" + Contains all blocks that can be used to build models. +""" + +from PyQt4.QtGui import * +from PyQt4.QtCore import * + +def uniqify(name, names): + newname, i = name, 1 + while newname in names: newname, i = name + str(i), i + 1 + return newname + +def enum(**enums): + return type('Enum', (), enums) + +Position = enum(TOP=0, TOP_RIGHT=1, RIGHT=2, BOTTOM_RIGHT=3, BOTTOM=4, BOTTOM_LEFT=5, LEFT=6, TOP_LEFT=7) + +def buildPath(pts): + path = QPainterPath(pts[0]) + for pt in pts[1:]: path.lineTo(pt) + return path + +def equalSpace(n, l, offset=15): + if n == 1: + return [l / 2] + elif n > 1: + return [offset + (l - offset*2)/(n - 1)*i for i in range(n)] + return [] + +class Connection(QGraphicsPathItem): + """ A connection between blocks """ + def __init__(self, fromPort=None, toPort=None): + super(Connection, self).__init__() + self.pos2 = self.fromPort = self.toPort = None + self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape) + pen = QPen(Qt.blue, 2, cap=Qt.RoundCap) + self.setPen(pen) + self.arrowhead = QGraphicsPathItem(self) + self.arrowhead.setPath(buildPath([QPointF(0.0, 0.0), QPointF(-6.0, 10.0), QPointF(6.0, 10.0), QPointF(0.0, 0.0)])) + self.arrowhead.setPen(pen) + self.arrowhead.setBrush(QBrush(pen.color())) + self.vias = [] + self.setFromPort(fromPort) + self.setToPort(toPort) + def getDict(self): + d = {} + d['fromBlock'] = self.fromPort.block.name + d['fromPort'] = self.fromPort.name + d['toBlock'] = self.toPort.block.name + d['toPort'] = self.toPort.name + return d + Dict = property(getDict) + def myDelete(self): + scene = self.scene() + if scene: + self.setFromPort(None) + self.setToPort(None) + scene.removeItem(self) + def setFromPort(self, fromPort): + if self.fromPort: + self.fromPort.posCallbacks.remove(self.setBeginPos) + self.fromPort.connection = None + self.fromPort = fromPort + if self.fromPort: + self.fromPort.connection = self + self.updateLineStukken() + self.fromPort.posCallbacks.append(self.setBeginPos) + def setToPort(self, toPort): + if self.toPort: + self.toPort.posCallbacks.remove(self.setEndPos) + self.toPort.connection = None + self.toPort = toPort + if self.toPort: + self.setEndPos(toPort.scenePos()) + self.toPort.connection = self + self.toPort.posCallbacks.append(self.setEndPos) + def getPos1(self): + if self.fromPort: + return self.fromPort.scenePos() + def setBeginPos(self, pos1): self.updateLineStukken() + def setEndPos(self, endpos): + self.pos2 = endpos + self.updateLineStukken() + def itemChange(self, change, value): + if change == self.ItemSelectedHasChanged: + for via in self.vias: + via.setVisible(value) + return super(Connection, self).itemChange(change, value) + def shape(self): return self.myshape + def updateLineStukken(self): + """ + This algorithm determines the optimal routing of all signals. + TODO: implement nice automatic line router + """ + pos1 = self.getPos1() + pos2 = self.pos2 + if pos1 is None or pos2 is None: + return + scene = self.scene() + vias = [pos1 + QPointF(20, 0)] + self.vias + [pos2 + QPointF(-20, 0)] + if scene: + litem = QGraphicsLineItem() + litem.setFlags(self.ItemIsSelectable) + scene.addItem(litem) + for p1, p2 in zip(vias[:-1], vias[1:]): + line = QLineF(p1, p2) + litem.setLine(line) + citems = scene.collidingItems(litem) + citems = [i for i in citems if type(i) is Block] + scene.removeItem(litem) + pts = [pos1] + vias + [pos2] + self.arrowhead.setPos(pos2) + self.arrowhead.setRotation(90) + p = buildPath(pts) + self.setPath(p) + """ Create a shape outline using the path stroker """ + s = super(Connection, self).shape() + pps = QPainterPathStroker() + pps.setWidth(10) + self.myshape = pps.createStroke(s).simplified() + +class PortItem(QGraphicsPathItem): + """ Represents a port to a subsystem """ + def __init__(self, name, block): + super(PortItem, self).__init__(block) + self.textItem = QGraphicsTextItem(self) + self.connection = None + self.block = block + self.setCursor(QCursor(Qt.CrossCursor)) + self.setPen(QPen(Qt.blue, 2, cap=Qt.RoundCap)) + self.name = name + self.posCallbacks = [] + self.setFlag(self.ItemSendsScenePositionChanges, True) + def getName(self): return self.textItem.toPlainText() + def setName(self, name): + self.textItem.setPlainText(name) + rect = self.textItem.boundingRect() + lw, lh = rect.width(), rect.height() + lx = 3 if type(self) is InputPort else -3 - lw + self.textItem.setPos(lx, -lh / 2) + name = property(getName, setName) + def getDict(self): + return {'name': self.name} + Dict = property(getDict) + def itemChange(self, change, value): + if change == self.ItemScenePositionHasChanged: + for cb in self.posCallbacks: cb(value) + return value + return super(PortItem, self).itemChange(change, value) + +class OutputPort(PortItem): + def __init__(self, name, block, d=10.0): + super(OutputPort, self).__init__(name, block) + self.setPath(buildPath([QPointF(0.0, -d), QPointF(d, 0), QPointF(0.0, d)])) + def mousePressEvent(self, event): + self.scene().startConnection(self) + +class InputPort(PortItem): + def __init__(self, name, block, d=10.0): + super(InputPort, self).__init__(name, block) + self.setPath(buildPath([QPointF(-d, -d), QPointF(0, 0), QPointF(-d, d)])) + +class Handle(QGraphicsEllipseItem): + """ A handle that can be moved by the mouse """ + def __init__(self, dx=10.0, parent=None): + super(Handle, self).__init__(QRectF(-0.5*dx,-0.5*dx,dx,dx), parent) + self.setBrush(QBrush(Qt.white)) + self.setFlags(self.ItemIsMovable) + self.setZValue(1) + self.setVisible(False) + self.setCursor(QCursor(Qt.SizeFDiagCursor)) + def mouseMoveEvent(self, event): + """ Move function without moving the other selected elements """ + p = self.mapToParent(event.pos()) + self.setPos(p) + +class ResizeSelectionHandle(Handle): + def __init__(self, position, block): + super(ResizeSelectionHandle, self).__init__(dx=12, parent=block) + self.position = position + self.block = block + if position in [Position.TOP_LEFT, Position.BOTTOM_RIGHT]: + self.setCursor(QCursor(Qt.SizeFDiagCursor)) + elif position in [Position.TOP_RIGHT, Position.BOTTOM_LEFT]: + self.setCursor(QCursor(Qt.SizeBDiagCursor)) + elif position in [Position.TOP, Position.BOTTOM]: + self.setCursor(QCursor(Qt.SizeVerCursor)) + elif position in [Position.LEFT, Position.RIGHT]: + self.setCursor(QCursor(Qt.SizeHorCursor)) + def mouseMoveEvent(self, event): + self.block.sizerMoveEvent(self, event.scenePos()) + +class Block(QGraphicsRectItem): + """ Represents a block in the diagram. """ + def __init__(self, name='Untitled', parent=None): + super(Block, self).__init__(parent) + self.selectionHandles = [ResizeSelectionHandle(i, self) for i in range(8)] + # Properties of the rectangle: + self.setPen(QPen(Qt.blue, 2)) + self.setBrush(QBrush(Qt.lightGray)) + self.setFlags(self.ItemIsSelectable | self.ItemIsMovable | self.ItemSendsScenePositionChanges) + self.setCursor(QCursor(Qt.PointingHandCursor)) + self.setAcceptHoverEvents(True) + self.label = QGraphicsTextItem(name, self) + self.name = name + # Create corner for resize: + button = QPushButton('+in') + button.clicked.connect(self.newInputPort) + self.buttonItemAddInput = QGraphicsProxyWidget(self) + self.buttonItemAddInput.setWidget(button) + self.buttonItemAddInput.setVisible(False) + button = QPushButton('+out') + button.clicked.connect(self.newOutputPort) + self.buttonItemAddOutput = QGraphicsProxyWidget(self) + self.buttonItemAddOutput.setWidget(button) + self.buttonItemAddOutput.setVisible(False) + # Inputs and outputs of the block: + self.inputs = [] + self.outputs = [] + self.changeSize(2,2) + def editParameters(self): + pd = ParameterDialog(self, self.window()) + pd.exec_() + def newInputPort(self): + names = [i.name for i in self.inputs + self.outputs] + self.addInput(InputPort(uniqify('in', names), self)) + def newOutputPort(self): + names = [i.name for i in self.inputs + self.outputs] + self.addOutput(OutputPort(uniqify('out', names), self)) + def setName(self, name): self.label.setPlainText(name) + def getName(self): return self.label.toPlainText() + name = property(getName, setName) + def getDict(self): + d = {'x': self.scenePos().x(), 'y': self.scenePos().y()} + rect = self.rect() + d.update({'width': rect.width(), 'height': rect.height()}) + d['name'] = self.name + d['inputs'] = [inp.Dict for inp in self.inputs] + d['outputs'] = [outp.Dict for outp in self.outputs] + return d + def setDict(self, d): + self.name = d['name'] + self.setPos(d['x'], d['y']) + self.changeSize(d['width'], d['height']) + for inp in d['inputs']: + self.addInput(InputPort(inp['name'], self)) + for outp in d['outputs']: + self.addOutput(OutputPort(outp['name'], self)) + Dict = property(getDict, setDict) + def addInput(self, i): + self.inputs.append(i) + self.updateSize() + def addOutput(self, o): + self.outputs.append(o) + self.updateSize() + def contextMenuEvent(self, event): + menu = QMenu() + pa = menu.addAction('Parameters') + pa.triggered.connect(self.editParameters) + menu.exec_(event.screenPos()) + def itemChange(self, change, value): + if change == self.ItemSelectedHasChanged: + for child in [self.buttonItemAddInput, self.buttonItemAddOutput]: + child.setVisible(value) + if value: + self.repositionAndShowHandles() + else: + [h.setVisible(False) for h in self.selectionHandles] + + return super(Block, self).itemChange(change, value) + def hoverEnterEvent(self, event): + if not self.isSelected(): + self.repositionAndShowHandles() + super(Block, self).hoverEnterEvent(event) + def hoverLeaveEvent(self, event): + if not self.isSelected(): + [h.setVisible(False) for h in self.selectionHandles] + super(Block, self).hoverLeaveEvent(event) + def myDelete(self): + for p in self.inputs + self.outputs: + if p.connection: p.connection.myDelete() + self.scene().removeItem(self) + def repositionAndShowHandles(self): + r = self.rect() + self.selectionHandles[Position.TOP_LEFT].setPos(r.topLeft()) + self.selectionHandles[Position.TOP].setPos(r.center().x(), r.top()) + self.selectionHandles[Position.TOP_RIGHT].setPos(r.topRight()) + self.selectionHandles[Position.RIGHT].setPos(r.right(), r.center().y()) + self.selectionHandles[Position.BOTTOM_RIGHT].setPos(r.bottomRight()) + self.selectionHandles[Position.BOTTOM].setPos(r.center().x(), r.bottom()) + self.selectionHandles[Position.BOTTOM_LEFT].setPos(r.bottomLeft()) + self.selectionHandles[Position.LEFT].setPos(r.left(), r.center().y()) + for h in self.selectionHandles: + h.setVisible(True) + def sizerMoveEvent(self, handle, pos): + r = self.rect().translated(self.pos()) + if handle.position == Position.TOP_LEFT: r.setTopLeft(pos) + elif handle.position == Position.TOP: r.setTop(pos.y()) + elif handle.position == Position.TOP_RIGHT: r.setTopRight(pos) + elif handle.position == Position.RIGHT: r.setRight(pos.x()) + elif handle.position == Position.BOTTOM_RIGHT: r.setBottomRight(pos) + elif handle.position == Position.BOTTOM: r.setBottom(pos.y()) + elif handle.position == Position.BOTTOM_LEFT: r.setBottomLeft(pos) + elif handle.position == Position.LEFT: r.setLeft(pos.x()) + else: + print('invalid position') + self.setCenterAndSize(r.center(), r.size()) + self.repositionAndShowHandles() + def updateSize(self): + rect = self.rect() + h, w = rect.height(), rect.width() + self.buttonItemAddInput.setPos(0, h + 4) + self.buttonItemAddOutput.setPos(w+10, h+4) + for inp, y in zip(self.inputs, equalSpace(len(self.inputs), h)): + inp.setPos(0.0, y) + for outp, y in zip(self.outputs, equalSpace(len(self.outputs), h)): + outp.setPos(w, y) + def setCenterAndSize(self, center, size): + self.changeSize(size.width(), size.height()) + p = QPointF(size.width(), size.height()) + self.setPos(center - p / 2) + def changeSize(self, w, h): + minw = 150 + minh = 50 + h = minh if h < minh else h + w = minw if w < minw else w + self.setRect(0.0, 0.0, w, h) + rect = self.label.boundingRect() + self.label.setPos((w - rect.width()) / 2, (h - rect.height()) / 2) + self.updateSize() + +class CodeBlock(Block): + def __init__(self, name='Untitled', parent=None): + super(CodeBlock, self).__init__(name, parent) + self.code = '' + def setDict(self, d): + super(CodeBlock, self).setDict(d) + self.code = d['code'] + def getDict(self): + d = super(CodeBlock, self).getDict() + d['code'] = self.code + return d + def gencode(self): + c = ['def {0}():'.format(self.name)] + if self.code: + c += indent(self.code.split('\n')) + else: + c += indent(['pass']) + return c + +class DiagramBlock(Block): + def __init__(self, name='Untitled', parent=None): + super(DiagramBlock, self).__init__(name, parent) + self.subModel = DiagramScene() + self.subModel.containingBlock = self + def setDict(self, d): + self.subModel.Dict = d['submodel'] + def mouseDoubleClickEvent(self, event): + # descent into child diagram + #self.editParameters() + print('descent') + scene = self.scene() + if scene: + for view in scene.views(): + view.diagram = self.subModel + view.zoomAll() + +class DiagramScene(QGraphicsScene): + """ A diagram scene consisting of blocks and connections """ + structureChanged = pyqtSignal() + def __init__(self): + super(DiagramScene, self).__init__() + self.startedConnection = None + + blocks = property(lambda sel: [i for i in sel.items() if isinstance(i, Block)]) + connections = property(lambda sel: [i for i in sel.items() if type(i) is Connection]) + def addItem(self, item): + super(DiagramScene, self).addItem(item) + if isinstance(item, Block): + self.structureChanged.emit() + def removeItem(self, item): + super(DiagramScene, self).removeItem(item) + if isinstance(item, Block): + self.structureChanged.emit() + def setDict(self, d): + for block in d['blocks']: + b = Block() + self.addItem(b) + b.Dict = block + for con in d['connections']: + fromPort = self.findPort(con['fromBlock'], con['fromPort']) + toPort = self.findPort(con['toBlock'], con['toPort']) + self.addItem(Connection(fromPort, toPort)) + def getDict(self): + return {'blocks': [b.Dict for b in self.blocks], 'connections': [c.Dict for c in self.connections]} + Dict = property(getDict, setDict) + def gencode(self): + c = [] + for b in self.blocks: + c += b.gencode() + for b in self.blocks: + c.append('{0}()'.format(b.name)) + return c + def findPort(self, blockname, portname): + block = self.findBlock(blockname) + if block: + for port in block.inputs + block.outputs: + if port.name == portname: return port + def findBlock(self, blockname): + for block in self.blocks: + if block.name == blockname: return block + def uniqify(self, name): + blocknames = [item.name for item in self.blocks] + return uniqify(name, blocknames) + def mouseMoveEvent(self, event): + if self.startedConnection: + pos = event.scenePos() + self.startedConnection.setEndPos(pos) + super(DiagramScene, self).mouseMoveEvent(event) + def mouseReleaseEvent(self, event): + if self.startedConnection: + for item in self.items(event.scenePos()): + if type(item) is InputPort and item.connection == None: + self.startedConnection.setToPort(item) + self.startedConnection = None + return + self.startedConnection.myDelete() + self.startedConnection = None + super(DiagramScene, self).mouseReleaseEvent(event) + def startConnection(self, port): + self.startedConnection = Connection(port, None) + pos = port.scenePos() + self.startedConnection.setEndPos(pos) + self.addItem(self.startedConnection) + def deleteItems(self): + for item in list(self.selectedItems()): item.myDelete() +
--- a/python/ppci/__init__.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/ppci/__init__.py Wed Nov 27 08:06:42 2013 +0100 @@ -12,4 +12,3 @@ from .common import SourceLocation, SourceRange, Token from .errors import CompilerError, DiagnosticsManager from .errors import printError -
--- a/python/ppci/common.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/ppci/common.py Wed Nov 27 08:06:42 2013 +0100 @@ -10,6 +10,7 @@ loc = SourceLocation('', 0, 0, 0) assert type(loc) is SourceLocation self.loc = loc + def __repr__(self): return 'Token({0}, {1})'.format(self.typ, self.val) @@ -26,4 +27,3 @@ SourceRange = namedtuple('SourceRange', ['p1', 'p2']) -
--- a/python/st-flash.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -#!/usr/bin/python - -import argparse, sys -import stlink, stm32 -import hexfile - -def hex2int(s): - if s.startswith('0x'): - s = s[2:] - return int(s, 16) - raise ValueError('Hexadecimal value must begin with 0x') - -parser = argparse.ArgumentParser( - description='ST-link flash utility by Windel Bouwman') -subparsers = parser.add_subparsers(title='commands', - description='possible commands', dest='command') - -readparser = subparsers.add_parser('read', help='read flash contents') -readparser.add_argument('filename', type=argparse.FileType('wb', 0)) -readparser.add_argument('address', type=hex2int) -readparser.add_argument('size', type=hex2int) - -writeparser = subparsers.add_parser('write', help='write flash contents') -writeparser.add_argument('filename', type=argparse.FileType('rb')) -writeparser.add_argument('address', type=hex2int) - -hexwriteparser = subparsers.add_parser('hexwrite', help='write hexfile to flash') -hexwriteparser.add_argument('hexfile', type=argparse.FileType('r')) - -verifyparser = subparsers.add_parser('verify', help='verify flash contents') -verifyparser.add_argument('filename', type=argparse.FileType('rb')) -verifyparser.add_argument('address', type=hex2int) - -eraseparser = subparsers.add_parser('erase', help='erase flash contents') - -args = parser.parse_args() -if not args.command: - parser.print_usage() - sys.exit(1) - -# In any command case, open a device: -stl = stlink.STLink2() -stl.open() - -# Enter the right mode: -if stl.CurrentMode == stlink.DFU_MODE: - stl.exitDfuMode() - -if stl.CurrentMode != stlink.DEBUG_MODE: - stl.enterSwdMode() - -if stl.ChipId != 0x10016413: - print('Only working on stm32f4discovery board for now.') - sys.exit(2) - -# Retrieve the connected device, if any: -dev = stl.createDevice() - -if args.command == 'read': - dev_content = dev.readFlash(args.address, args.size) - args.filename.write(dev_content) -elif args.command == 'write': - content = args.filename.read() - dev.writeFlash(args.address, content) -elif args.command == 'hexwrite': - hf = hexfile.HexFile() - hf.load(args.hexfile) - r = hf.regions[0] - dev.writeFlash(r.address, r.data) -elif args.command == 'verify': - content = args.filename.read() - dev.verifyFlash(args.address, content) -elif args.command == 'erase': - dev.eraseFlash() -else: - print('unknown command', args.command) - -stl.reset() -stl.run() -stl.exitDebugMode() -
--- a/python/st-util.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -#!/usr/bin/python - -import sys -from PyQt4.QtCore import * -from PyQt4.QtGui import * -import stlink, devices, stm32, usb -from devices import Interface, Device -from hexedit import HexEdit - -class InformationDialog(QDialog): - def __init__(self, parent): - super().__init__(parent) - self.setWindowTitle('Info') - fl = QFormLayout(self) - if parent.stl: - fl.addRow('ST link version:', QLabel(parent.stl.Version)) - fl.addRow('Chip id:', QLabel('0x{0:X}'.format(parent.stl.ChipId))) - fl.addRow('Current mode:', QLabel(parent.stl.CurrentModeString)) - fl.addRow('Status:', QLabel(parent.stl.StatusString)) - -class RegisterModel(QAbstractTableModel): - def __init__(self): - super().__init__() - self.regCount = 15 - self.device = None - - def rowCount(self, parent): - if parent.isValid(): - return 0 - if self.device: - return 21 # TODO make variable - else: - return 0 - - def setDevice(self, dev): - self.device = dev - self.modelReset.emit() - - def columnCount(self, parent): - if parent.isValid(): - return 0 - return 2 - - def data(self, index, role): - if index.isValid(): - row, col = index.row(), index.column() - if role == Qt.DisplayRole: - if col == 0: - if row == 15: - return 'PC' - elif row == 14: - return 'LR' - elif row == 13: - return 'SP' - else: - return 'R{0}'.format(row) - elif col == 1: - v = self.device.iface.read_reg(row) - return '0x{0:X}'.format(v) - - def setData(self, index, value, role): - if index.isValid(): - row = index.row() - col = index.column() - if role == Qt.EditRole and col == 1: - value = int(value, 16) - self.device.iface.write_reg(row, value) - return True - return False - - def flags(self, index): - if index.isValid(): - row = index.row() - col = index.column() - if col == 1: - return super().flags(index) | Qt.ItemIsEditable - return super().flags(index) - - def refresh(self): - if self.device: - fromIndex = self.index(0, 1) - toIndex = self.index(21, 1) - self.dataChanged.emit(fromIndex, toIndex) - - -class RegisterView(QTableView): - def __init__(self): - super().__init__() - self.mdl = RegisterModel() - self.setModel(self.mdl) - - def refresh(self): - if self.mdl.device: - self.setEnabled(not self.mdl.device.Running) - self.mdl.refresh() - - -class MemoryView(QWidget): - BlockSize = 0x100 - def __init__(self): - super().__init__() - l = QVBoxLayout(self) - l2 = QHBoxLayout() - l2.addWidget(QLabel('Address')) - self.addressLine = QLineEdit() - self.addressLine.setInputMask('Hhhhhhhh') - l2.addWidget(self.addressLine) - upButton = QPushButton('up') - l2.addWidget(upButton) - upButton.clicked.connect(self.doUp) - downButton = QPushButton('down') - downButton.clicked.connect(self.doDown) - l2.addWidget(downButton) - l.addLayout(l2) - self.device = None - self.hexEdit = HexEdit() - self.Address = 0x8000000 - l.addWidget(self.hexEdit) - self.addressLine.returnPressed.connect(self.refresh) - - def refresh(self): - address = self.Address - if self.device: - data = self.device.iface.read_mem32(address, self.BlockSize) - else: - data = bytearray(self.BlockSize) - self.hexEdit.bv.Data = data - self.hexEdit.bv.Offset = address - - def getAddress(self): - txt = self.addressLine.text() - return int(txt, 16) - - def doUp(self): - self.Address -= self.BlockSize - - def doDown(self): - self.Address += self.BlockSize - - def setAddress(self, address): - self.addressLine.setText('{0:08X}'.format(address)) - self.refresh() - Address = property(getAddress, setAddress) - def setDevice(self, dev): - self.device = dev - self.Address = 0x8000000 - - -class DebugToolbar(QToolBar): - statusChange = pyqtSignal() - codePosition = pyqtSignal(int) - def __init__(self): - super().__init__() - self.device = None - # generate actions: - def genAction(name, callback): - a = QAction(name, self) - a.triggered.connect(callback) - self.addAction(a) - return a - self.stepAction = genAction('Step', self.doStep) - self.runAction = genAction('Run', self.doRun) - self.stopAction = genAction('Stop', self.doHalt) - self.resetAction = genAction('Reset', self.doReset) - self.enableTraceAction = genAction('Enable trace', self.doEnableTrace) - self.updateEnables() - def updateEnables(self): - if self.device: - self.resetAction.setEnabled(True) - self.enableTraceAction.setEnabled(True) - self.runAction.setEnabled(not self.device.Running) - self.stepAction.setEnabled(not self.device.Running) - self.stopAction.setEnabled(self.device.Running) - self.statusChange.emit() - if not self.device.Running: - PC = 15 - v = self.device.iface.read_reg(PC) - self.codePosition.emit(v) - else: - self.resetAction.setEnabled(False) - self.enableTraceAction.setEnabled(False) - self.runAction.setEnabled(False) - self.stepAction.setEnabled(False) - self.stopAction.setEnabled(False) - def doStep(self): - self.device.iface.step() - self.updateEnables() - def doReset(self): - self.device.iface.reset() - self.updateEnables() - def doRun(self): - self.device.iface.run() - self.updateEnables() - def doHalt(self): - self.device.iface.halt() - self.updateEnables() - def doEnableTrace(self): - self.device.iface.traceEnable() - self.updateEnables() - def setDevice(self, dev): - self.device = dev - self.updateEnables() - - -class FlashTool(QWidget): - def __init__(self): - super().__init__() - # TODO! - - -class DeviceTreeModel(QAbstractItemModel): - def __init__(self): - super().__init__() - self.chipPixmap = QPixmap('icons/chip.png').scaled(32, 32) - self.hardwarePixmap = QPixmap('icons/hardware.png').scaled(32, 32) - self.refresh() - def refresh(self): - """ Check all usb interfaces for interfaces """ - self.interfaces = devices.createInterfaces() - self.devices = [] - self.modelReset.emit() - def addDevice(self, device): - if device.iface in [lambda d: d.iface for d in self.devices]: - print('device already open') - return - self.devices.append(device) - self.modelReset.emit() - def index(self, row, column, parent): - if parent.isValid(): - ip = parent.internalPointer() - if isinstance(ip, Interface): - devs = [d for d in self.devices if d.iface is ip] - return self.createIndex(row, column, devs[row]) - else: - iface = self.interfaces[row] - return self.createIndex(row, column, iface) - return idx - def parent(self, index): - if index.isValid(): - ip = index.internalPointer() - if isinstance(ip, Interface): - return QModelIndex() - elif isinstance(ip, Device): - iface = ip.iface - row = self.interfaces.index(iface) - return self.createIndex(row, 0, iface) - return QModelIndex() - def rowCount(self, parent): - if parent.isValid(): - # non-root level: - ip = parent.internalPointer() - if isinstance(ip, Interface): - devs = [d for d in self.devices if d.iface is ip] - return len(devs) - else: - # root level: - return len(self.interfaces) - return 0 - def columnCount(self, parent): - return 1 - def data(self, index, role): - if index.isValid(): - ip = index.internalPointer() - if role == Qt.DisplayRole: - return str(ip) - elif role == Qt.DecorationRole: - if isinstance(ip, Interface): - return self.hardwarePixmap - if isinstance(ip, Device): - return self.chipPixmap - -class DeviceExplorer(QTreeView): - """ Lists all interfaces plugged in and allows selection """ - deviceSelected = pyqtSignal(Device) - def __init__(self): - super().__init__() - self.mdl = DeviceTreeModel() - self.setModel(self.mdl) - self.activated.connect(self.openItem) - self.header().close() - self.customContextMenuRequested.connect(self.openMenu) - self.setContextMenuPolicy(Qt.CustomContextMenu) - def openItem(self, idx): - if idx.isValid(): - ip = idx.internalPointer() - if isinstance(ip, Interface): - if not ip.IsOpen: - try: - ip.open() - except usb.UsbError as e: - QMessageBox.critical(self, "Error", 'Error opening interface: "{0}"'.format(e)) - else: - # Try to get a device: - self.mdl.addDevice(ip.createDevice()) - if isinstance(ip, Device): - self.deviceSelected.emit(ip) - def openMenu(self, pt): - idx = self.indexAt(pt) - menu = QMenu() - menu.addAction('Refresh', self.mdl.refresh) - if idx.isValid(): - ip = idx.internalPointer() - if isinstance(ip, Interface): - if ip.IsOpen: - def closeInterface(): - self.mdl.closeInterface(ip) - menu.addAction('Close', closeInterface) - else: - def openInterface(): - ip.open() - # Try to get a device: - self.mdl.addDevice(ip.createDevice()) - menu.addAction('Open', openInterface) - elif isinstance(ip, Device): - def selectDevice(): - self.deviceSelected.emit(ip) - menu.addAction('Select', selectDevice) - menu.exec(self.mapToGlobal(pt)) - -class StUtil(QMainWindow): - connected = pyqtSignal(bool) - def __init__(self): - super().__init__() - self.stl = None - def buildAction(name, callback, shortcut=None): - a = QAction(name, self) - a.triggered.connect(callback) - if shortcut: - a.setShortcut(shortcut) - return a - mb = self.menuBar() - fileMenu = mb.addMenu("File") - self.connectAction = buildAction('Connect', self.connect) - fileMenu.addAction(self.connectAction) - self.disconnectAction = buildAction('Disconnect', self.disconnect) - fileMenu.addAction(self.disconnectAction) - - self.miscMenu = mb.addMenu("Misc") - infoAction = buildAction('Info', self.info) - self.miscMenu.addAction(infoAction) - - sb = self.statusBar() - - devexplr = DeviceExplorer() - self.setCentralWidget(devexplr) - devexplr.deviceSelected.connect(self.handleDeviceSelected) - - self.connected.connect(self.handleConnectedChange) - self.connected.emit(False) - def handleDeviceSelected(self, dev): - self.dev = dev - self.handleConnectedChange(True) - def handleConnectedChange(self, state): - self.miscMenu.setEnabled(state) - self.connectAction.setEnabled(not state) - self.disconnectAction.setEnabled(state) - msg = 'Connected!' if state else 'Disconnected!' - self.statusBar().showMessage(msg) - def info(self): - infoDialog = InformationDialog(self) - infoDialog.exec() - def connect(self): - try: - self.stl = stlink.STLink() - self.stl.open() - except (stlink.STLinkException, usb.UsbError) as e: - QMessageBox.warning(self, "Error", str(e)) - self.stl = None - if self.stl: - self.connected.emit(True) - def disconnect(self): - if self.stl: - self.stl.close() - self.connected.emit(False) - self.stl = None - -if __name__ == '__main__': - app = QApplication(sys.argv) - stu = StUtil() - stu.show() - app.exec() -
--- a/python/stlink.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -import struct, time -from usb import UsbContext, UsbDevice -from devices import Interface, STLinkException, registerInterface -import adi - -""" - More or less copied from: - https://github.com/texane/stlink - Tracing from: - https://github.com/obe1line/stlink-trace - -""" -ST_VID, STLINK2_PID = 0x0483, 0x3748 - -def checkDevice(device): - return device.VendorId == ST_VID and device.ProductId == STLINK2_PID - -DFU_MODE, MASS_MODE, DEBUG_MODE = 0, 1, 2 - -CORE_RUNNING = 0x80 -CORE_HALTED = 0x81 - -# Commands: -GET_VERSION = 0xf1 -DEBUG_COMMAND = 0xf2 -DFU_COMMAND = 0xf3 -GET_CURRENT_MODE = 0xf5 - -# dfu commands: -DFU_EXIT = 0x7 - -# debug commands: -DEBUG_ENTER = 0x20 -DEBUG_EXIT = 0x21 -DEBUG_ENTER_SWD = 0xa3 -DEBUG_GETSTATUS = 0x01 -DEBUG_FORCEDEBUG = 0x02 -DEBUG_RESETSYS = 0x03 -DEBUG_READALLREGS = 0x04 -DEBUG_READREG = 0x5 -DEBUG_WRITEREG = 0x6 -DEBUG_READMEM_32BIT = 0x7 -DEBUG_WRITEMEM_32BIT = 0x8 -DEBUG_RUNCORE = 0x9 -DEBUG_STEPCORE = 0xa - -JTAG_WRITEDEBUG_32BIT = 0x35 -JTAG_READDEBUG_32BIT = 0x36 -TRACE_GET_BYTE_COUNT = 0x42 - -# cortex M3 -CM3_REG_CPUID = 0xE000ED00 - -@registerInterface((ST_VID, STLINK2_PID)) -class STLink2(Interface): - """ STlink2 interface implementation. """ - def __init__(self, stlink2=None): - self.devHandle = None - if not stlink2: - context = UsbContext() - stlink2s = list(filter(checkDevice, context.DeviceList)) - if not stlink2s: - raise STLinkException('Could not find an ST link 2 interface') - if len(stlink2s) > 1: - print('More then one stlink2 found, picking first one') - stlink2 = stlink2s[0] - assert isinstance(stlink2, UsbDevice) # Nifty type checking - assert checkDevice(stlink2) - self.stlink2 = stlink2 - def __del__(self): - if self.IsOpen: - if self.CurrentMode == DEBUG_MODE: - self.exitDebugMode() - self.close() - def __str__(self): - if self.IsOpen: - return 'STlink2 device version {0}'.format(self.Version) - else: - return 'STlink2 device' - def open(self): - if self.IsOpen: - return - self.devHandle = self.stlink2.open() - if self.devHandle.Configuration != 1: - self.devHandle.Configuration = 1 - self.devHandle.claimInterface(0) - - # First initialization: - if self.CurrentMode == DFU_MODE: - self.exitDfuMode() - if self.CurrentMode != DEBUG_MODE: - self.enterSwdMode() - #self.reset() - def close(self): - if self.IsOpen: - self.devHandle.close() - self.devHandle = None - @property - def IsOpen(self): - return self.devHandle != None - # modes: - def getCurrentMode(self): - cmd = bytearray(16) - cmd[0] = GET_CURRENT_MODE - reply = self.send_recv(cmd, 2) # Expect 2 bytes back - return reply[0] - CurrentMode = property(getCurrentMode) - @property - def CurrentModeString(self): - modes = {DFU_MODE: 'dfu', MASS_MODE: 'massmode', DEBUG_MODE:'debug'} - return modes[self.CurrentMode] - def exitDfuMode(self): - cmd = bytearray(16) - cmd[0:2] = DFU_COMMAND, DFU_EXIT - self.send_recv(cmd) - def enterSwdMode(self): - cmd = bytearray(16) - cmd[0:3] = DEBUG_COMMAND, DEBUG_ENTER, DEBUG_ENTER_SWD - self.send_recv(cmd) - def exitDebugMode(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_EXIT - self.send_recv(cmd) - - def getVersion(self): - cmd = bytearray(16) - cmd[0] = GET_VERSION - data = self.send_recv(cmd, 6) # Expect 6 bytes back - # Parse 6 bytes into various versions: - b0, b1, b2, b3, b4, b5 = data - stlink_v = b0 >> 4 - jtag_v = ((b0 & 0xf) << 2) | (b1 >> 6) - swim_v = b1 & 0x3f - vid = (b3 << 8) | b2 - pid = (b5 << 8) | b4 - return 'stlink={0} jtag={1} swim={2} vid:pid={3:04X}:{4:04X}'.format(\ - stlink_v, jtag_v, swim_v, vid, pid) - Version = property(getVersion) - - @property - def ChipId(self): - return self.read_debug32(0xE0042000) - @property - def CpuId(self): - u32 = self.read_debug32(CM3_REG_CPUID) - implementer_id = (u32 >> 24) & 0x7f - variant = (u32 >> 20) & 0xf - part = (u32 >> 4) & 0xfff - revision = u32 & 0xf - return implementer_id, variant, part, revision - def getStatus(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_GETSTATUS - reply = self.send_recv(cmd, 2) - return reply[0] - Status = property(getStatus) - @property - def StatusString(self): - s = self.Status - statii = {CORE_RUNNING: 'CORE RUNNING', CORE_HALTED: 'CORE HALTED'} - if s in statii: - return statii[s] - return 'Unknown status' - - def reset(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_RESETSYS - self.send_recv(cmd, 2) - - # debug commands: - def step(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_STEPCORE - self.send_recv(cmd, 2) - def run(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_RUNCORE - self.send_recv(cmd, 2) - def halt(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_FORCEDEBUG - self.send_recv(cmd, 2) - - # Tracing: - def traceEnable(self): - self.write_debug32(0xE000EDF0, 0xA05F0003) - - # Enable TRCENA: - DEMCR = 0xE000EDFC - v = self.read_debug32(DEMCR) - v |= (1 << 24) - self.write_debug32(DEMCR, v) - - # ?? Enable write?? - self.write_debug32(0xE0002000, 0x2) # - - # DBGMCU_CR: - self.write_debug32(0xE0042004, 0x27) # Enable trace in async mode - - # TPIU config: - self.write_debug32(0xE0040004, 0x00000001) # current port size register --> 1 == port size = 1 - self.write_debug32(0xE0040010, 0x23) # random clock divider?? - self.write_debug32(0xE00400F0, 0x2) # selected pin protocol (2 == NRZ) - self.write_debug32(0xE0040304, 0x100) # continuous formatting - - # ITM config: - self.write_debug32(0xE0000FB0, 0xC5ACCE55) # Unlock write access to ITM - self.write_debug32(0xE0000F80, 0x00010005) # ITM Enable, sync enable, ATB=1 - self.write_debug32(0xE0000E00, 0xFFFFFFFF) # Enable all trace ports in ITM - self.write_debug32(0xE0000E40, 0x0000000F) # Set privilege mask for all 32 ports. - def writePort0(self, v32): - self.write_debug32(0xE0000000, v32) - def getTraceByteCount(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, 0x42 - reply = self.send_recv(cmd, 2) - return struct.unpack('<H', reply[0:2])[0] - def readTraceData(self): - bsize = self.getTraceByteCount() - if bsize > 0: - td = self.recv_ep3(bsize) - print(td) - else: - print('no trace data') - - # Helper 1 functions: - def write_debug32(self, address, value): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, JTAG_WRITEDEBUG_32BIT - cmd[2:10] = struct.pack('<II', address, value) - r = self.send_recv(cmd, 2) - def read_debug32(self, address): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, JTAG_READDEBUG_32BIT - cmd[2:6] = struct.pack('<I', address) # pack into u32 little endian - reply = self.send_recv(cmd, 8) - return struct.unpack('<I', reply[4:8])[0] - def write_reg(self, reg, value): - cmd = bytearray(16) - cmd[0:3] = DEBUG_COMMAND, DEBUG_WRITEREG, reg - cmd[3:7] = struct.pack('<I', value) - r = self.send_recv(cmd, 2) - def read_reg(self, reg): - cmd = bytearray(16) - cmd[0:3] = DEBUG_COMMAND, DEBUG_READREG, reg - reply = self.send_recv(cmd, 4) - return struct.unpack('<I', reply)[0] - def read_all_regs(self): - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_READALLREGS - reply = self.send_recv(cmd, 84) - fmt = '<' + 'I' * 21 # unpack 21 register values - return list(struct.unpack(fmt, reply)) - def write_mem32(self, address, content): - assert len(content) % 4 == 0 - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_WRITEMEM_32BIT - cmd[2:8] = struct.pack('<IH', address, len(content)) - self.send_recv(cmd) - self.send_recv(content) - def read_mem32(self, address, length): - assert length % 4 == 0 - cmd = bytearray(16) - cmd[0:2] = DEBUG_COMMAND, DEBUG_READMEM_32BIT - cmd[2:8] = struct.pack('<IH', address, length) - reply = self.send_recv(cmd, length) # expect memory back! - return reply - - # Helper 2 functions: - def send_recv(self, tx, rxsize=0): - """ Helper function that transmits and receives data in bulk mode. """ - # TODO: we could use here the non-blocking libusb api. - tx = bytes(tx) - #assert len(tx) == 16 - self.devHandle.bulkWrite(2, tx) # write to endpoint 2 - if rxsize > 0: - return self.devHandle.bulkRead(1, rxsize) # read from endpoint 1 - def recv_ep3(self, rxsize): - return self.devHandle.bulkRead(3, rxsize) - -if __name__ == '__main__': - # Test program - sl = STLink2() - sl.open() - sl.reset() - print('version:', sl.Version) - print('mode before doing anything:', sl.CurrentModeString) - if sl.CurrentMode == DFU_MODE: - sl.exitDfuMode() - sl.enterSwdMode() - print('mode after entering swd mode:', sl.CurrentModeString) - - i = sl.ChipId - print('chip id: 0x{0:X}'.format(i)) - print('cpu: {0}'.format(sl.CpuId)) - - print('status: {0}'.format(sl.StatusString)) - - # test registers: - sl.write_reg(0, 0xdeadbeef) - sl.write_reg(1, 0xcafebabe) - sl.write_reg(2, 0xc0ffee) - sl.write_reg(3, 0x1337) - sl.write_reg(5, 0x1332) - sl.write_reg(6, 0x12345) - assert sl.read_reg(3) == 0x1337 - assert sl.read_reg(5) == 0x1332 - assert sl.read_reg(6) == 0x12345 - regs = sl.read_all_regs() - for i in range(len(regs)): - print('R{0}=0x{1:X}'.format(i, regs[i])) - - print('tracing') - sl.traceEnable() - sl.run() - sl.writePort0(0x1337) # For test - time.sleep(0.1) - td = sl.readTraceData() - print('trace data:', td) - - # Test CoreSight registers: - idr4 = sl.read_debug32(0xE0041fd0) - print('idr4 =', idr4) - - print('== ADI ==') - a = adi.Adi(sl) - a.parseRomTable(0xE00FF000) # why is rom table at 0xE00FF000? - print('== ADI ==') - - # Detect ROM table: - id4 = sl.read_debug32(0xE00FFFD0) - id5 = sl.read_debug32(0xE00FFFD4) - id6 = sl.read_debug32(0xE00FFFD8) - id7 = sl.read_debug32(0xE00FFFDC) - id0 = sl.read_debug32(0xE00FFFE0) - id1 = sl.read_debug32(0xE00FFFE4) - id2 = sl.read_debug32(0xE00FFFE8) - id3 = sl.read_debug32(0xE00FFFEC) - pIDs = [id0, id1, id2, id3, id4, id5, id6, id7] - print(pIDs) - - print('reading from 0xE00FF000') - scs = sl.read_debug32(0xE00FF000) - print('scs {0:08X}'.format(scs)) - dwt = sl.read_debug32(0xE00FF004) - print('dwt {0:08X}'.format(dwt)) - fpb = sl.read_debug32(0xE00FF008) - print('fpb {0:08X}'.format(fpb)) - itm = sl.read_debug32(0xE00FF00C) - print('itm {0:08X}'.format(itm)) - tpiu = sl.read_debug32(0xE00FF010) - print('tpiu {0:08X}'.format(tpiu)) - etm = sl.read_debug32(0xE00FF014) - print('etm {0:08X}'.format(etm)) - assert sl.read_debug32(0xE00FF018) == 0x0 # end marker - - devid = sl.read_debug32(0xE0040FC8) - print('TPIU_DEVID: {0:X}'.format(devid)) - devtype = sl.read_debug32(0xE0040FCC) - print('TPIU_TYPEID: {0:X}'.format(devtype)) - - sl.exitDebugMode() - print('mode at end:', sl.CurrentModeString) - - sl.close() - print('Test succes!') -
--- a/python/stm32.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -import time -import logging -from devices import Device, registerDevice, STLinkException, Interface -import stlink - -# F4 specifics: -STM32_FLASH_BASE = 0x08000000 -STM32_SRAM_BASE = 0x20000000 - -# flash registers: -FLASH_F4_REGS_ADDR = 0x40023c00 -FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04 -FLASH_F4_SR = FLASH_F4_REGS_ADDR + 0x0c -FLASH_F4_CR = FLASH_F4_REGS_ADDR + 0x10 - -FLASH_F4_CR_START = 16 -FLASH_F4_CR_LOCK = 31 -FLASH_CR_PG = 0 -FLASH_F4_CR_SER = 1 -FLASH_CR_MER = 2 -FLASH_F4_CR_SNB = 3 -FLASH_F4_CR_SNB_MASK = 0x38 -FLASH_F4_SR_BSY = 16 - -class Stm32F4(Device): - """ - Implementation of the specifics of the STM32F4xx device series. - """ - def __init__(self, iface): - super().__init__(iface) - self.logger = logging.getLogger('stm32') - - def __str__(self): - return 'STM32F4 device size=0x{1:X} id=0x{0:X}'.format(\ - self.UID, self.FlashSize) - - def calculate_F4_sector(self, address): - sectorstarts = [] - a = STM32_FLASH_BASE - for sectorsize in self.sectorsizes: - sectorstarts.append(a) - a += sectorsize - # linear search: - sec = 0 - while sec < len(self.sectorsizes) and address >= sectorstarts[sec]: - sec += 1 - sec -= 1 # one back. - return sec, self.sectorsizes[sec] - - def calcSectors(self, address, size): - off = 0 - sectors = [] - while off < size: - sectornum, sectorsize = self.calculate_F4_sector(address + off) - sectors.append((sectornum, sectorsize)) - off += sectorsize - return sectors - - # Device registers: - @property - def UID(self): - uid_base = 0x1FFF7A10 - uid1 = self.iface.read_debug32(uid_base) - uid2 = self.iface.read_debug32(uid_base + 0x4) - uid3 = self.iface.read_debug32(uid_base + 0x8) - return (uid3 << 64) | (uid2 << 32) | uid1 - - @property - def FlashSize(self): - f_id = self.iface.read_debug32(0x1FFF7A22) - f_id = f_id >> 16 - return f_id * 1024 - - @property - def Running(self): - return self.iface.Status == stlink.CORE_RUNNING - - # flashing commands: - def writeFlash(self, address, content): - flashsize = self.FlashSize - pagesize = min(self.sectorsizes) - - # Check address range: - if address < STM32_FLASH_BASE: - raise STLinkException('Flashing below flash start') - if address + len(content) > STM32_FLASH_BASE + flashsize: - raise STLinkException('Flashing above flash size') - if address & 1 == 1: - raise STLinkException('Unaligned flash') - if len(content) & 1 == 1: - self.logger.warning('unaligned length, padding with zero') - content += bytes([0]) - if address & (pagesize - 1) != 0: - raise STLinkException('Address not aligned with pagesize') - # erase required space - sectors = self.calcSectors(address, len(content)) - self.logger.info('erasing {0} sectors'.format(len(sectors))) - for sector, secsize in sectors: - self.logger.info('erasing sector {0} of {1} bytes'.format(sector, secsize)) - self.eraseFlashSector(sector) - # program pages: - self.unlockFlashIf() - self.writeFlashCrPsiz(2) # writes are 32 bits aligned - self.setFlashCrPg() - self.logger.info('writing {0} bytes'.format(len(content))) - offset = 0 - t1 = time.time() - while offset < len(content): - size = len(content) - offset - if size > 0x8000: - size = 0x8000 - chunk = content[offset:offset + size] - while len(chunk) % 4 != 0: - chunk = chunk + bytes([0]) - # Use simple mem32 writes: - self.iface.write_mem32(address + offset, chunk) - offset += size - self.logger.info('{}%'.format(offset*100/len(content))) - self.logger.info('Done!') - self.lockFlash() - # verfify program: - self.verifyFlash(address, content) - - def eraseFlashSector(self, sector): - self.waitFlashBusy() - self.unlockFlashIf() - self.writeFlashCrSnb(sector) - self.setFlashCrStart() - self.waitFlashBusy() - self.lockFlash() - - def eraseFlash(self): - self.waitFlashBusy() - self.unlockFlashIf() - self.setFlashCrMer() - self.setFlashCrStart() - self.waitFlashBusy() - self.clearFlashCrMer() - self.lockFlash() - - def verifyFlash(self, address, content): - device_content = self.readFlash(address, len(content)) - ok = content == device_content - if ok: - self.logger.info('Verify: OK') - else: - self.logger.warning('Verify: Mismatch') - - def readFlash(self, address, size): - self.logger.info('Reading {1} bytes from 0x{0:X}'.format(address, size)) - offset = 0 - tmp_size = 0x1800 - image = bytes() - while offset < size: - # Correct for last page: - if offset + tmp_size > size: - tmp_size = size - offset - - # align size to 4 bytes: - aligned_size = tmp_size - while aligned_size % 4 != 0: - aligned_size += 1 - - mem = self.iface.read_mem32(address + offset, aligned_size) - image += mem[:tmp_size] - - # indicate progress: - self.logger.info('{}%'.format(100*len(image) / size)) - - # increase for next piece: - offset += tmp_size - assert size == len(image) - self.logger.info('Done!') - return image - - def waitFlashBusy(self): - """ block until flash operation completes. """ - while self.isFlashBusy(): - time.sleep(0.01) - - def isFlashLocked(self): - mask = 1 << FLASH_F4_CR_LOCK - return self.Cr & mask == mask - - def unlockFlashIf(self): - FLASH_KEY1, FLASH_KEY2 = 0x45670123, 0xcdef89ab - if self.isFlashLocked(): - self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY1) - self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY2) - if self.isFlashLocked(): - raise STLinkException('Failed to unlock') - - def lockFlash(self): - self.Cr = self.Cr | (1 << FLASH_F4_CR_LOCK) - - def readFlashSr(self): - return self.iface.read_debug32(FLASH_F4_SR) - - def readFlashCr(self): - return self.iface.read_debug32(FLASH_F4_CR) - - def writeFlashCr(self, x): - self.iface.write_debug32(FLASH_F4_CR, x) - - Cr = property(readFlashCr, writeFlashCr) - - def writeFlashCrSnb(self, sector): - x = self.Cr - x &= ~FLASH_F4_CR_SNB_MASK - x |= sector << FLASH_F4_CR_SNB - x |= 1 << FLASH_F4_CR_SER - self.Cr = x - - def setFlashCrMer(self): - self.Cr = self.Cr | (1 << FLASH_CR_MER) - - def setFlashCrPg(self): - self.Cr = self.Cr | (1 << FLASH_CR_PG) - - def writeFlashCrPsiz(self, n): - x = self.Cr - x &= (0x3 << 8) - x |= n << 8 - self.Cr = x - - def clearFlashCrMer(self): - x = self.Cr - x &= ~(1 << FLASH_CR_MER) - self.Cr = x - - def setFlashCrStart(self): - self.Cr = self.Cr | (1 << FLASH_F4_CR_START) - - def isFlashBusy(self): - mask = 1 << FLASH_F4_SR_BSY - sr = self.readFlashSr() - # Check for error bits: - errorbits = {} - errorbits[7] = 'Programming sequence error' - errorbits[6] = 'Programming parallelism error' - errorbits[5] = 'Programming alignment error' - errorbits[4] = 'Write protection error' - errorbits[1] = 'Operation error' - #errorbits[0] = 'End of operation' - for bit, msg in errorbits.items(): - if sr & (1 << bit) == (1 << bit): - raise STLinkException(msg) - return sr & mask == mask - - -@registerDevice(0x10016413) -class Stm32F40x(Stm32F4): - """ STM32F40x and STM32F41x device series """ - def __init__(self, iface): - super().__init__(iface) - # Assert the proper size for this device: - assert self.FlashSize == 0x100000 - """ - from 0x8000000 to 0x80FFFFF - 4 sectors of 0x4000 (16 kB) - 1 sector of 0x10000 (64 kB) - 7 of 0x20000 (128 kB) - """ - self.sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7
--- a/python/target/__init__.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/__init__.py Wed Nov 27 08:06:42 2013 +0100 @@ -2,7 +2,18 @@ from .basetarget import Nop, Instruction, Label, Target, Comment, Alignment from .basetarget import Imm32, DebugInfo -#from .armtarget import armtarget + +from .armtarget import ArmTarget +from .armframe import ArmFrame +from .arminstructionselector import ArmInstructionSelector + +from .msp430 import msp430target + +# Instance: +armtarget = ArmTarget() +armtarget.ins_sel = ArmInstructionSelector() +armtarget.FrameClass = ArmFrame + #from .msp430target import msp430target -#target_list = [armtarget, msp430target] +target_list = [armtarget]
--- a/python/target/armframe.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/armframe.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,22 +1,17 @@ import ir -from ppci import CompilerError from .basetarget import Label, Comment, Alignment, LabelRef, DebugInfo, Nop -from .basetarget import Imm32, Imm3 -import .armtarget as arm -from .instructionselector import InstructionSelector -import irmach -from irmach import AbstractInstruction as makeIns -import asm +from .basetarget import Imm7 +from irmach import AbstractInstruction as makeIns, Frame +from .arminstructions import Dcd, AddSp, SubSp, Push, Pop, Mov2 +from .arminstructions import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP -class ArmFrame(irmach.Frame): - """ - Arm specific frame for functions. - """ +class ArmFrame(Frame): + """ Arm specific frame for functions. """ def __init__(self, name): # We use r7 as frame pointer. super().__init__(name) - self.regs = [arm.r0, arm.r1, arm.r2, arm.r3, arm.r4, arm.r5, arm.r6] + self.regs = [R0, R1, R2, R3, R4, R5, R6] self.rv = ir.Temp('special_RV') self.p1 = ir.Temp('special_P1') self.p2 = ir.Temp('special_P2') @@ -25,12 +20,12 @@ self.fp = ir.Temp('special_FP') # Pre-colored registers: self.tempMap = {} - self.tempMap[self.rv] = arm.r0 - self.tempMap[self.p1] = arm.r1 - self.tempMap[self.p2] = arm.r2 - self.tempMap[self.p3] = arm.r3 - self.tempMap[self.p4] = arm.r4 - self.tempMap[self.fp] = arm.r7 + self.tempMap[self.rv] = R0 + self.tempMap[self.p1] = R1 + self.tempMap[self.p2] = R2 + self.tempMap[self.p3] = R3 + self.tempMap[self.p4] = R4 + self.tempMap[self.fp] = R7 self.locVars = {} self.parMap = {} # Literal pool: @@ -67,153 +62,17 @@ Add code for the prologue and the epilogue. Add a label, the return instruction and the stack pointer adjustment for the frame. """ - self.instructions.insert(0, makeIns(arm.Label(self.name))) - self.instructions.insert(1, makeIns(arm.push_ins(arm.RegisterSet({arm.lr, arm.r7})))) + self.instructions.insert(0, makeIns(Label(self.name))) + self.instructions.insert(1, makeIns(Push({LR, R7}))) # Reserve stack space for locals: - self.instructions.insert(2, makeIns(arm.subspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize)))) + self.instructions.insert(2, makeIns(SubSp(SP, SP, Imm7(self.stacksize)))) # Setup frame pointer: - self.instructions.insert(3, makeIns(arm.movregreg_ext_ins(arm.r7, arm.sp))) + self.instructions.insert(3, makeIns(Mov2(R7, SP))) # Stack grows downwards - self.instructions.append(makeIns(arm.addspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize)))) - self.instructions.append(makeIns(arm.pop_ins(arm.RegisterSet({arm.pc, arm.r7})))) + self.instructions.append(makeIns(AddSp(SP, SP, Imm7(self.stacksize)))) + self.instructions.append(makeIns(Pop({PC, R7}))) # Add constant literals: self.instructions.append(makeIns(Alignment(4))) # Align at 4 bytes for ln, v in self.constants: - self.instructions.append(makeIns(arm.Label(ln))) - self.instructions.append(makeIns(arm.dcd_ins(v))) - - -class ArmInstructionSelector(InstructionSelector): - """ Instruction selector for the arm architecture """ - def munchExpr(self, e): - if isinstance(e, ir.Alloc): - return 0 - elif isinstance(e, ir.Binop) and e.operation == '+' and \ - isinstance(e.b, ir.Const) and e.b.value < 8: - a = self.munchExpr(e.a) - d = self.newTmp() - c = Imm3(e.b.value) - self.emit(arm.addregregimm3_ins, others=[c], dst=[d], src=[a]) - return d - elif isinstance(e, ir.Binop) and e.operation == '+': - a = self.munchExpr(e.a) - b = self.munchExpr(e.b) - d = self.newTmp() - self.emit(arm.addregs_ins, dst=[d], src=[a, b]) - return d - elif isinstance(e, ir.Binop) and e.operation == '-' and \ - isinstance(e.b, ir.Const) and e.b.value < 8: - a = self.munchExpr(e.a) - d = self.newTmp() - c = Imm3(e.b.value) - self.emit(arm.subregregimm3_ins, others=[c], dst=[d], src=[a]) - return d - elif isinstance(e, ir.Binop) and e.operation == '-': - a = self.munchExpr(e.a) - b = self.munchExpr(e.b) - d = self.newTmp() - self.emit(arm.subregs_ins, dst=[d], src=[a, b]) - return d - elif isinstance(e, ir.Binop) and e.operation == '|': - a = self.munchExpr(e.a) - b = self.munchExpr(e.b) - d = self.newTmp() - self.move(d, a) - self.emit(arm.orrregs_ins, dst=[], src=[b, d]) - return d - elif isinstance(e, ir.Binop) and e.operation == '<<': - a = self.munchExpr(e.a) - b = self.munchExpr(e.b) - d = self.newTmp() - self.move(d, a) - self.emit(arm.lslregs_ins, dst=[], src=[b, d]) # TODO: is d a source variable? - return d - elif isinstance(e, ir.Binop) and e.operation == '*': - a = self.munchExpr(e.a) - b = self.munchExpr(e.b) - d = self.newTmp() - self.move(d, a) - # this mul instruction has operands swapped: - self.emit(arm.mulregreg_ins, dst=[d], src=[b, d]) - return d - elif isinstance(e, ir.Const) and e.value < 256: - d = self.newTmp() - self.emit(arm.mov_imm8_ins, others=[arm.Imm8(e.value)], dst=[d]) - return d - elif isinstance(e, ir.Const) and e.value < (2**31): - d = self.newTmp() - ln = LabelRef(self.frame.addConstant(e.value)) - self.emit(arm.ldr_pcrel, others=[ln], dst=[d]) - return d - elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \ - e.e.operation == '+' and isinstance(e.e.b, ir.Const): - base = self.munchExpr(e.e.a) - d = self.newTmp() - c = e.e.b.value - self.emit(arm.loadimm5_ins, others=[c], src=[base], dst=[d]) - return d - elif isinstance(e, ir.Mem): - # Load from memory - base = self.munchExpr(e.e) - d = self.newTmp() - self.emit(arm.loadimm5_ins, others=[0], src=[base], dst=[d]) - return d - elif isinstance(e, ir.Temp): - return e - elif isinstance(e, ir.Call): - # Move arguments into proper locations: - reguses = [] - for i, a in enumerate(e.arguments): - loc = self.frame.argLoc(i) - m = ir.Move(loc, a) - self.munchStm(m) - if isinstance(loc, ir.Temp): - reguses.append(loc) - self.emit(arm.bl_ins(LabelRef(e.f.name)), src=reguses, dst=[self.frame.rv]) - d = self.newTmp() - self.move(d, self.frame.rv) - return d - else: - raise NotImplementedError('Expr --> {}'.format(e)) - - def munchStm(self, s): - if isinstance(s, ir.Terminator): - pass - elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \ - isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \ - isinstance(s.dst.e.b, ir.Const): - a = self.munchExpr(s.dst.e.a) - val = self.munchExpr(s.src) - c = s.dst.e.b.value - self.emit(arm.storeimm5_ins, others=[c], src=[a, val]) - elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): - memloc = self.munchExpr(s.dst.e) - val = self.munchExpr(s.src) - self.emit(arm.storeimm5_ins, others=[0], src=[memloc, val]) - elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): - val = self.munchExpr(s.src) - dreg = s.dst - self.move(dreg, val) - elif isinstance(s, ir.Exp): - # Generate expression code and discard the result. - x = self.munchExpr(s.e) - self.emit(Nop(), src=[x]) - elif isinstance(s, ir.Jump): - tgt = self.targets[s.target] - self.emit(arm.b_ins(LabelRef(s.target.name)), jumps=[tgt]) - elif isinstance(s, ir.CJump): - a = self.munchExpr(s.a) - b = self.munchExpr(s.b) - self.emit(arm.cmp_ins, src=[a, b]) - ntgt = self.targets[s.lab_no] - ytgt = self.targets[s.lab_yes] - jmp_ins = makeIns(arm.b_ins(LabelRef(s.lab_no.name)), jumps=[ntgt]) - opnames = {'<': arm.blt_ins, '>':arm.bgt_ins, '==':arm.beq_ins} - op = opnames[s.cond](LabelRef(s.lab_yes.name)) - self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough - self.emit2(jmp_ins) - else: - raise NotImplementedError('Stmt --> {}'.format(s)) - - def move(self, dst, src): - self.emit(arm.movregreg_ext_ins, src=[src], dst=[dst]) + self.instructions.append(makeIns(Label(ln))) + self.instructions.append(makeIns(Dcd(v)))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/arminstructions.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,758 @@ +import struct +from asmnodes import ASymbol, AInstruction, ANumber, AUnop, ABinop +from .basetarget import Register, Instruction, Target, Label, LabelRef +from .basetarget import Imm32, Imm8, Imm7, Imm3 + + +def u16(h): + return struct.pack('<H', h) + +def u32(x): + return struct.pack('<I', x) + +# Operands: + +class ArmRegister(Register): + def __init__(self, num, name): + super().__init__(name) + self.num = num + + def __repr__(self): + return self.name + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + name = vop.name + regs = {} + for r in registers: + regs[r.name] = r + if name in regs: + r = regs[name] + if isinstance(r, cls): + return r + + +class Reg8Op(ArmRegister): + pass + + +class Reg16Op(ArmRegister): + pass + + +R0 = Reg8Op(0, 'r0') +R1 = Reg8Op(1, 'r1') +R2 = Reg8Op(2, 'r2') +R3 = Reg8Op(3, 'r3') +R4 = Reg8Op(4, 'r4') +R5 = Reg8Op(5, 'r5') +R6 = Reg8Op(6, 'r6') +R7 = Reg8Op(7, 'r7') +# Other registers: +# TODO +SP = ArmRegister(13, 'sp') +LR = ArmRegister(14, 'lr') +PC = ArmRegister(15, 'pc') + +registers = [R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC] + + +class RegSpOp: + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + if vop.name.lower() == 'sp': + return cls() + + +def getRegNum(n): + for r in registers: + if r.num == n: + return r + + +def getRegisterRange(n1, n2): + regs = [] + if n1.num < n2.num: + for n in range(n1.num, n2.num + 1): + r = getRegNum(n) + assert r + regs.append(r) + return regs + + +def isRegOffset(regname, x, y): + if type(x) is ASymbol and type(y) is ANumber and x.name.upper() == regname: + return y.number + elif type(y) is ASymbol and type(x) is ANumber and y.name.upper() == regname: + return x.number + + +class MemRegXRel: + def __init__(self, offset): + assert offset % 4 == 0 + self.offset = offset + + def __repr__(self): + return '[{}, #{}]'.format(self.regname, self.offset) + + @classmethod + def Create(cls, vop): + if type(vop) is AUnop and vop.operation == '[]' and type(vop.arg) is ABinop and vop.arg.op == '+': + vop = vop.arg # descent + offset = isRegOffset(cls.regname, vop.arg1, vop.arg2) + if type(offset) is int: + if offset % 4 == 0: + offset = vop.arg2.number + return cls(offset) + elif type(vop) is ASymbol and vop.name.upper() == self.regname: + return cls(0) + + +class MemSpRel(MemRegXRel): + regname = 'SP' + + +class MemR8Rel: + def __init__(self, basereg, offset): + assert type(basereg) is Reg8Op + assert type(offset) is int + self.basereg = basereg + self.offset = offset + + def __repr__(self): + return '[{}, #{}]'.format(self.basereg, self.offset) + + @classmethod + def Create(cls, vop): + if type(vop) is AUnop and vop.operation == '[]': + vop = vop.arg # descent + if type(vop) is ABinop: + if vop.op == '+' and type(vop.arg1) is ASymbol and type(vop.arg2) is ANumber: + offset = vop.arg2.number + if offset > 120: + return + basereg = Reg8Op.Create(vop.arg1) + if not basereg: + return + else: + return + elif type(vop) is ASymbol: + offset = 0 + basereg = Reg8Op.Create(vop) + if not basereg: + return + else: + return + return cls(getRegNum(basereg.num), offset) + + +class RegisterSet: + def __init__(self, regs): + assert type(regs) is set + self.regs = regs + + def __repr__(self): + return ','.join([str(r) for r in self.regs]) + + @classmethod + def Create(cls, vop): + assert type(vop) is AUnop and vop.operation == '{}' + assert type(vop.arg) is list + regs = set() + for arg in vop.arg: + if type(arg) is ASymbol: + reg = ArmRegister.Create(arg) + if not reg: + return + regs.add(reg) + elif type(arg) is ABinop and arg.op == '-': + reg1 = ArmRegister.Create(arg.arg1) + reg2 = ArmRegister.Create(arg.arg2) + if not reg1: + return + if not reg2: + return + for r in getRegisterRange(reg1, reg2): + regs.add(r) + else: + raise Exception('Cannot be') + return cls(regs) + + def registerNumbers(self): + return [r.num for r in self.regs] + + + +# Instructions: + +class ArmInstruction(Instruction): + pass + + +allins = [] + + +def instruction(i): + allins.append(i) + return i + + +@instruction +class Dcd(ArmInstruction): + mnemonic = 'dcd' + operands = (Imm32,) + def __init__(self, expr): + if isinstance(expr, Imm32): + self.expr = expr.imm + self.label = None + elif isinstance(expr, LabelRef): + self.expr = 0 + self.label = expr + elif isinstance(expr, int): + self.expr = expr + self.label = None + else: + raise NotImplementedError() + + def resolve(self, f): + if self.label: + self.expr = f(self.label.name) + + def encode(self): + return u32(self.expr) + + def __repr__(self): + return 'DCD 0x{0:X}'.format(self.expr) + + +@instruction +class nop_ins(ArmInstruction): + mnemonic = 'nop' + operands = tuple() + + def encode(self): + return bytes() + + def __repr__(self): + return 'NOP' + + +# Memory related + +class LS_imm5_base(ArmInstruction): + """ ??? Rt, [Rn, imm5] """ + operands = (Reg8Op, MemR8Rel) + def __init__(self, rt, memop): + assert memop.offset % 4 == 0 + self.imm5 = memop.offset >> 2 + self.rn = memop.basereg.num + self.rt = rt + self.memloc = memop + assert self.rn < 8 + assert self.rt.num < 8 + + def encode(self): + Rn = self.rn + Rt = self.rt.num + imm5 = self.imm5 + + h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt + return u16(h) + + + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc) + + +@instruction +class Str2(LS_imm5_base): + mnemonic = 'STR' + opcode = 0xC + + @classmethod + def fromim(cls, im): + mem = MemR8Rel(im.src[0], im.others[0]) + return cls(im.src[1], mem) + + +@instruction +class Ldr2(LS_imm5_base): + mnemonic = 'LDR' + opcode = 0xD + + @classmethod + def fromim(cls, im): + mem = MemR8Rel(im.src[0], im.others[0]) + return cls(im.dst[0], mem) + +class ls_sp_base_imm8(ArmInstruction): + operands = (Reg8Op, MemSpRel) + def __init__(self, rt, memop): + self.rt = rt + self.offset = memop.offset + + def encode(self): + rt = self.rt.num + assert rt < 8 + imm8 = self.offset >> 2 + assert imm8 < 256 + h = (self.opcode << 8) | (rt << 8) | imm8 + return u16(h) + + def __repr__(self): + return '{} {}, [sp,#{}]'.format(self.mnemonic, self.rt, self.offset) + +def align(x, m): + while ((x % m) != 0): + x = x + 1 + return x + + +@instruction +class Ldr3(ArmInstruction): + """ ldr Rt, LABEL, load value from pc relative position """ + mnemonic = 'ldr' + operands = (Reg8Op, LabelRef) + def __init__(self, rt, label): + assert isinstance(label, LabelRef) + self.rt = rt + self.label = label + self.offset = 0 + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.others[0]) + + def resolve(self, f): + la = f(self.label.name) + sa = align(self.address + 2, 4) + self.offset = (la - sa) + if self.offset < 0: + self.offset = 0 + + def encode(self): + rt = self.rt.num + assert rt < 8 + assert self.offset % 4 == 0 + imm8 = self.offset >> 2 + assert imm8 < 256 + assert imm8 >= 0 + h = (0x9 << 11) | (rt << 8) | imm8 + return u16(h) + + def __repr__(self): + return 'LDR {}, {}'.format(self.rt, self.label.name) + + +@instruction +class Ldr1(ls_sp_base_imm8): + """ ldr Rt, [SP, imm8] """ + mnemonic = 'LDR' + opcode = 0x98 + + +@instruction +class Str1(ls_sp_base_imm8): + """ str Rt, [SP, imm8] """ + mnemonic = 'STR' + opcode = 0x90 + + +@instruction +class Mov3(ArmInstruction): + """ mov Rd, imm8, move immediate value into register """ + mnemonic = 'mov' + opcode = 4 # 00100 Rd(3) imm8 + operands = (Reg8Op, Imm8) + def __init__(self, rd, imm): + if type(imm) is int: + imm = Imm8(imm) + assert type(imm) is Imm8 + self.imm = imm.imm + assert type(rd) is Reg8Op, str(type(rd)) + self.rd = rd + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.others[0]) + + def encode(self): + rd = self.rd.num + opcode = self.opcode + imm8 = self.imm + h = (opcode << 11) | (rd << 8) | imm8 + return u16(h) + + def __repr__(self): + return 'MOV {}, {}'.format(self.rd, self.imm) + + + +# Arithmatics: + + + +class regregimm3_base(ArmInstruction): + operands = (Reg8Op, Reg8Op, Imm3) + def __init__(self, rd, rn, imm3): + self.rd = rd + self.rn = rn + assert type(imm3) is Imm3 + self.imm3 = imm3 + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0], im.others[0]) + + def encode(self): + rd = self.rd.num + rn = self.rn.num + imm3 = self.imm3.imm + opcode = self.opcode + h = (self.opcode << 9) | (imm3 << 6) | (rn << 3) | rd + return u16(h) + + def __repr__(self): + return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm3.imm) + +@instruction +class addregregimm3_ins(regregimm3_base): + """ add Rd, Rn, imm3 """ + mnemonic = 'add' + opcode = 0b0001110 + + +@instruction +class subregregimm3_ins(regregimm3_base): + """ sub Rd, Rn, imm3 """ + mnemonic = 'sub' + opcode = 0b0001111 + + +class regregreg_base(ArmInstruction): + """ ??? Rd, Rn, Rm """ + operands = (Reg8Op, Reg8Op, Reg8Op) + def __init__(self, rd, rn, rm): + self.rd = rd + self.rn = rn + self.rm = rm + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0], im.src[1]) + + def encode(self): + rd = self.rd.num + rn = self.rn.num + rm = self.rm.num + h = (self.opcode << 9) | (rm << 6) | (rn << 3) | rd + return u16(h) + + def __repr__(self): + return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) + + +@instruction +class Add(regregreg_base): + mnemonic = 'ADD' + opcode = 0b0001100 + + +@instruction +class Sub(regregreg_base): + mnemonic = 'SUB' + opcode = 0b0001101 + + +@instruction +class Mov2(ArmInstruction): + """ mov rd, rm """ + operands = (ArmRegister, ArmRegister) + mnemonic = 'MOV' + def __init__(self, rd, rm): + self.rd = rd + self.rm = rm + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0]) + + def encode(self): + Rd = self.rd.num & 0x7 + D = (self.rd.num >> 3) & 0x1 + Rm = self.rm.num + opcode = 0b01000110 + return u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd) + + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) + + +@instruction +class mulregreg_ins(ArmInstruction): + """ mul Rn, Rdm """ + operands = (Reg8Op, Reg8Op) + mnemonic = 'MUL' + def __init__(self, rn, rdm): + self.rn = rn + self.rdm = rdm + + @classmethod + def fromim(cls, im): + assert im.src[1] is im.dst[0] + return cls(im.src[0], im.dst[0]) + + def encode(self): + rn = self.rn.num + rdm = self.rdm.num + opcode = 0b0100001101 + h = (opcode << 6) | (rn << 3) | rdm + return u16(h) + + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) + + +class regreg_base(ArmInstruction): + """ ??? Rdn, Rm """ + operands = (Reg8Op, Reg8Op) + # TODO: integrate with the code gen interface: + src = (0, 1) + dst = (0,) + def __init__(self, rdn, rm): + self.rdn = rdn + self.rm = rm + + @classmethod + def fromim(cls, im): + return cls(im.src[0], im.src[1]) + + def encode(self): + rdn = self.rdn.num + rm = self.rm.num + h = (self.opcode << 6) | (rm << 3) | rdn + return u16(h) + + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm) + + +@instruction +class movregreg_ins(regreg_base): + """ mov Rd, Rm (reg8 operands) """ + mnemonic = 'mov' + opcode = 0 + + +@instruction +class And(regreg_base): + mnemonic = 'AND' + opcode = 0b0100000000 + + +@instruction +class Orr(regreg_base): + mnemonic = 'ORR' + opcode = 0b0100001100 + + +@instruction +class Cmp(regreg_base): + mnemonic = 'CMP' + opcode = 0b0100001010 + + +@instruction +class Lsl(regreg_base): + mnemonic = 'LSL' + opcode = 0b0100000010 + + +@instruction +class cmpregimm8_ins(ArmInstruction): + """ cmp Rn, imm8 """ + mnemonic = 'cmp' + opcode = 5 # 00101 + operands = (Reg8Op, Imm8) + def __init__(self, rn, imm): + self.rn = rn + self.imm = imm + + def encode(self): + rn = self.rn.num + imm = self.imm.imm + opcode = self.opcode + h = (opcode << 11) | (rn << 8) | imm + return u16(h) + + +# Jumping: + +def wrap_negative(x, bits): + b = struct.unpack('<I', struct.pack('<i', x))[0] + mask = (1 << bits) - 1 + return b & mask + +class jumpBase_ins(ArmInstruction): + operands = (LabelRef,) + def __init__(self, target_label): + assert type(target_label) is LabelRef + self.target = target_label + self.offset = 0 + + def resolve(self, f): + la = f(self.target.name) + sa = self.address + 4 + self.offset = (la - sa) + + def __repr__(self): + return '{} {}'.format(self.mnemonic, self.target.name) + + +@instruction +class B(jumpBase_ins): + mnemonic = 'B' + def encode(self): + imm11 = wrap_negative(self.offset >> 1, 11) + h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode + return u16(h) + + +@instruction +class Bl(jumpBase_ins): + mnemonic = 'BL' + def encode(self): + imm32 = wrap_negative(self.offset >> 1, 32) + imm11 = imm32 & 0x7FF + imm10 = (imm32 >> 11) & 0x3FF + j1 = 1 # TODO: what do these mean? + j2 = 1 + s = (imm32 >> 24) & 0x1 + h1 = (0b11110 << 11) | (s << 10) | imm10 + h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 + return u16(h1) + u16(h2) + + +class cond_base_ins(jumpBase_ins): + def encode(self): + imm8 = wrap_negative(self.offset >> 1, 8) + h = (0b1101 << 12) | (self.cond << 8) | imm8 + return u16(h) + + +@instruction +class Beq(cond_base_ins): + mnemonic = 'beq' + cond = 0 + + +@instruction +class Bne(cond_base_ins): + mnemonic = 'bne' + cond = 1 + + +@instruction +class Blt(cond_base_ins): + mnemonic = 'blt' + cond = 0b1011 + + +@instruction +class Bgt(cond_base_ins): + mnemonic = 'bgt' + cond = 0b1100 + + +@instruction +class Push(ArmInstruction): + operands = (RegisterSet,) + mnemonic = 'push' + + def __init__(self, regs): + if type(regs) is set: + regs = RegisterSet(regs) + assert (type(regs),) == self.operands, (type(regs),) + self.regs = regs + + def __repr__(self): + return '{0} {{{1}}}'.format(self.mnemonic, self.regs) + + def encode(self): + reg_list = 0 + M = 0 + for n in self.regs.registerNumbers(): + if n < 8: + reg_list |= (1 << n) + elif n == 14: + M = 1 + else: + raise NotImplementedError('not implemented for this register') + h = (0x5a << 9) | (M << 8) | reg_list + return u16(h) + + +@instruction +class Pop(ArmInstruction): + operands = (RegisterSet,) + mnemonic = 'pop' + + def __init__(self, regs): + if type(regs) is set: + regs = RegisterSet(regs) + assert (type(regs),) == self.operands, (type(regs),) + self.regs = regs + + def __repr__(self): + return '{0} {{{1}}}'.format(self.mnemonic, self.regs) + + def encode(self): + reg_list = 0 + P = 0 + for n in self.regs.registerNumbers(): + if n < 8: + reg_list |= (1 << n) + elif n == 15: + P = 1 + else: + raise NotImplementedError('not implemented for this register') + h = (0x5E << 9) | (P << 8) | reg_list + return u16(h) + + +@instruction +class Yield(ArmInstruction): + operands = () + mnemonic = 'yield' + + def encode(self): + return u16(0xbf10) + +# misc: + +# add/sub SP: +class addspsp_base(ArmInstruction): + operands = (RegSpOp, RegSpOp, Imm7) + def __init__(self, _sp, _sp2, imm7): + self.imm7 = imm7.imm + assert self.imm7 % 4 == 0 + self.imm7 >>= 2 + + def encode(self): + return u16((self.opcode << 7) |self.imm7) + + def __repr__(self): + return '{} sp, sp, {}'.format(self.mnemonic, self.imm7 << 2) + +@instruction +class AddSp(addspsp_base): + mnemonic = 'add' + opcode = 0b101100000 + + +@instruction +class SubSp(addspsp_base): + mnemonic = 'sub' + opcode = 0b101100001
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/arminstructionselector.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,144 @@ +import ir +from irmach import AbstractInstruction as makeIns +from .basetarget import Label, Comment, Alignment, LabelRef, DebugInfo, Nop +from .instructionselector import InstructionSelector +from .arminstructions import Orr, Lsl, Str2, Ldr2, Ldr3, B, Bl, Bgt, Blt, Beq +from .arminstructions import Mov2, Mov3 +from .arminstructions import Add, Sub, Cmp +from .basetarget import Imm8, Imm7, Imm3 + + +class ArmInstructionSelector(InstructionSelector): + """ Instruction selector for the arm architecture """ + def munchExpr(self, e): + if isinstance(e, ir.Alloc): + return 0 + elif isinstance(e, ir.Binop) and e.operation == '+' and \ + isinstance(e.b, ir.Const) and e.b.value < 8: + a = self.munchExpr(e.a) + d = self.newTmp() + c = Imm3(e.b.value) + self.emit(arm.addregregimm3_ins, others=[c], dst=[d], src=[a]) + return d + elif isinstance(e, ir.Binop) and e.operation == '+': + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) + d = self.newTmp() + self.emit(Add, dst=[d], src=[a, b]) + return d + elif isinstance(e, ir.Binop) and e.operation == '-' and \ + isinstance(e.b, ir.Const) and e.b.value < 8: + a = self.munchExpr(e.a) + d = self.newTmp() + c = Imm3(e.b.value) + self.emit(arm.subregregimm3_ins, others=[c], dst=[d], src=[a]) + return d + elif isinstance(e, ir.Binop) and e.operation == '-': + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) + d = self.newTmp() + self.emit(Sub, dst=[d], src=[a, b]) + return d + elif isinstance(e, ir.Binop) and e.operation == '|': + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) + d = self.newTmp() + self.move(d, a) + self.emit(Orr, dst=[], src=[b, d]) + return d + elif isinstance(e, ir.Binop) and e.operation == '<<': + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) + d = self.newTmp() + self.move(d, a) + self.emit(Lsl, dst=[], src=[b, d]) # TODO: is d a source variable? + return d + elif isinstance(e, ir.Binop) and e.operation == '*': + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) + d = self.newTmp() + self.move(d, a) + # this mul instruction has operands swapped: + self.emit(arm.mulregreg_ins, dst=[d], src=[b, d]) + return d + elif isinstance(e, ir.Const) and e.value < 256: + d = self.newTmp() + self.emit(Mov3, others=[Imm8(e.value)], dst=[d]) + return d + elif isinstance(e, ir.Const) and e.value < (2**31): + d = self.newTmp() + ln = LabelRef(self.frame.addConstant(e.value)) + self.emit(Ldr3, others=[ln], dst=[d]) + return d + elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \ + e.e.operation == '+' and isinstance(e.e.b, ir.Const): + base = self.munchExpr(e.e.a) + d = self.newTmp() + c = e.e.b.value + self.emit(Ldr2, others=[c], src=[base], dst=[d]) + return d + elif isinstance(e, ir.Mem): + # Load from memory + base = self.munchExpr(e.e) + d = self.newTmp() + self.emit(Ldr2, others=[0], src=[base], dst=[d]) + return d + elif isinstance(e, ir.Temp): + return e + elif isinstance(e, ir.Call): + # Move arguments into proper locations: + reguses = [] + for i, a in enumerate(e.arguments): + loc = self.frame.argLoc(i) + m = ir.Move(loc, a) + self.munchStm(m) + if isinstance(loc, ir.Temp): + reguses.append(loc) + self.emit(Bl(LabelRef(e.f.name)), src=reguses, dst=[self.frame.rv]) + d = self.newTmp() + self.move(d, self.frame.rv) + return d + else: + raise NotImplementedError('Expr --> {}'.format(e)) + + def munchStm(self, s): + if isinstance(s, ir.Terminator): + pass + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \ + isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \ + isinstance(s.dst.e.b, ir.Const): + a = self.munchExpr(s.dst.e.a) + val = self.munchExpr(s.src) + c = s.dst.e.b.value + self.emit(Str2, others=[c], src=[a, val]) + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): + memloc = self.munchExpr(s.dst.e) + val = self.munchExpr(s.src) + self.emit(Str2, others=[0], src=[memloc, val]) + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): + val = self.munchExpr(s.src) + dreg = s.dst + self.move(dreg, val) + elif isinstance(s, ir.Exp): + # Generate expression code and discard the result. + x = self.munchExpr(s.e) + self.emit(Nop(), src=[x]) + elif isinstance(s, ir.Jump): + tgt = self.targets[s.target] + self.emit(B(LabelRef(s.target.name)), jumps=[tgt]) + elif isinstance(s, ir.CJump): + a = self.munchExpr(s.a) + b = self.munchExpr(s.b) + self.emit(Cmp, src=[a, b]) + ntgt = self.targets[s.lab_no] + ytgt = self.targets[s.lab_yes] + jmp_ins = makeIns(B(LabelRef(s.lab_no.name)), jumps=[ntgt]) + opnames = {'<': Blt, '>':Bgt, '==':Beq} + op = opnames[s.cond](LabelRef(s.lab_yes.name)) + self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough + self.emit2(jmp_ins) + else: + raise NotImplementedError('Stmt --> {}'.format(s)) + + def move(self, dst, src): + self.emit(Mov2, src=[src], dst=[dst])
--- a/python/target/armtarget.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/armtarget.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,759 +1,32 @@ import struct -import types -import ir -from asmnodes import ASymbol, ANumber, AUnop, ABinop -from ppci import CompilerError from .basetarget import Register, Instruction, Target, Label, LabelRef from .basetarget import Imm32, Imm8, Imm7, Imm3 -from .armframe import ArmFrame, ArmInstructionSelector +from .arminstructions import allins, Reg8Op, ArmRegister +from .arminstructions import Dcd, B +from .arminstructions import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP """ ARM target description. """ # TODO: encode this in DSL (domain specific language) # TBD: is this required? - -def u16(h): - return struct.pack('<H', h) - -def u32(x): - return struct.pack('<I', x) - -armtarget = Target('arm') -armtarget.InstructionSelector = ArmInstructionSelector -armtarget.Frame = ArmFrame - -class ArmRegister(Register): - def __init__(self, num, name): - super().__init__(name) - self.num = num - - def __repr__(self): - return self.name - - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - name = vop.name - regs = {} - for r in armtarget.registers: - regs[r.name] = r - if name in regs: - r = regs[name] - if isinstance(r, cls): - return r - - -class Reg8Op(ArmRegister): - pass - - -class Reg16Op(ArmRegister): - pass - - -class RegSpOp: - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - if vop.name.lower() == 'sp': - return cls() - -def getRegNum(n): - for r in armtarget.registers: - if r.num == n: - return r - -def getRegisterRange(n1, n2): - regs = [] - if n1.num < n2.num: - for n in range(n1.num, n2.num + 1): - r = getRegNum(n) - assert r - regs.append(r) - return regs - -def isRegOffset(regname, x, y): - if type(x) is ASymbol and type(y) is ANumber and x.name.upper() == regname: - return y.number - elif type(y) is ASymbol and type(x) is ANumber and y.name.upper() == regname: - return x.number - - -class MemRegXRel: - def __init__(self, offset): - assert offset % 4 == 0 - self.offset = offset - - def __repr__(self): - return '[{}, #{}]'.format(self.regname, self.offset) - - @classmethod - def Create(cls, vop): - if type(vop) is AUnop and vop.operation == '[]' and type(vop.arg) is ABinop and vop.arg.op == '+': - vop = vop.arg # descent - offset = isRegOffset(cls.regname, vop.arg1, vop.arg2) - if type(offset) is int: - if offset % 4 == 0: - offset = vop.arg2.number - return cls(offset) - elif type(vop) is ASymbol and vop.name.upper() == self.regname: - return cls(0) - - -class MemSpRel(MemRegXRel): - regname = 'SP' - - -class MemR8Rel: - def __init__(self, basereg, offset): - assert type(basereg) is Reg8Op - assert type(offset) is int - self.basereg = basereg - self.offset = offset - - def __repr__(self): - return '[{}, #{}]'.format(self.basereg, self.offset) - - @classmethod - def Create(cls, vop): - if type(vop) is AUnop and vop.operation == '[]': - vop = vop.arg # descent - if type(vop) is ABinop: - if vop.op == '+' and type(vop.arg1) is ASymbol and type(vop.arg2) is ANumber: - offset = vop.arg2.number - if offset > 120: - return - basereg = Reg8Op.Create(vop.arg1) - if not basereg: - return - else: - return - elif type(vop) is ASymbol: - offset = 0 - basereg = Reg8Op.Create(vop) - if not basereg: - return - else: - return - return cls(getRegNum(basereg.num), offset) - -class RegisterSet: - def __init__(self, regs): - assert type(regs) is set - self.regs = regs - - def __repr__(self): - return ','.join([str(r) for r in self.regs]) - - @classmethod - def Create(cls, vop): - assert type(vop) is AUnop and vop.operation == '{}' - assert type(vop.arg) is list - regs = set() - for arg in vop.arg: - if type(arg) is ASymbol: - reg = ArmRegister.Create(arg) - if not reg: - return - regs.add(reg) - elif type(arg) is ABinop and arg.op == '-': - reg1 = ArmRegister.Create(arg.arg1) - reg2 = ArmRegister.Create(arg.arg2) - if not reg1: - return - if not reg2: - return - for r in getRegisterRange(reg1, reg2): - regs.add(r) - else: - raise Exception('Cannot be') - return cls(regs) - - def registerNumbers(self): - return [r.num for r in self.regs] - -def makeReg(cls, num, name): - r = cls(num, name) - armtarget.registers.append(r) - return r - -# 8 bit registers: -r0 = makeReg(Reg8Op, 0, 'r0') -r1 = makeReg(Reg8Op, 1, 'r1') -r2 = makeReg(Reg8Op, 2, 'r2') -r3 = makeReg(Reg8Op, 3, 'r3') -r4 = makeReg(Reg8Op, 4, 'r4') -r5 = makeReg(Reg8Op, 5, 'r5') -r6 = makeReg(Reg8Op, 6, 'r6') -r7 = makeReg(Reg8Op, 7, 'r7') -# Other registers: -# TODO -sp = makeReg(ArmRegister, 13, 'sp') -lr = makeReg(ArmRegister, 14, 'lr') -pc = makeReg(ArmRegister, 15, 'pc') - -# Sanity checks: -assert isinstance(sp, ArmRegister) -assert isinstance(r3, ArmRegister) -assert ArmRegister.Create(ASymbol('r3')) is r3 -assert ArmRegister.Create(ASymbol('sp')) is sp - - -class ArmInstruction(Instruction): - pass - - -@armtarget.instruction -class dcd_ins(ArmInstruction): - mnemonic = 'dcd' - operands = (Imm32,) - def __init__(self, expr): - if isinstance(expr, Imm32): - self.expr = expr.imm - self.label = None - elif isinstance(expr, LabelRef): - self.expr = 0 - self.label = expr - elif isinstance(expr, int): - self.expr = expr - self.label = None - else: - raise NotImplementedError() - - def resolve(self, f): - if self.label: - self.expr = f(self.label.name) - - def encode(self): - return u32(self.expr) - - def __repr__(self): - return 'DCD 0x{0:X}'.format(self.expr) - - -@armtarget.instruction -class nop_ins(ArmInstruction): - mnemonic = 'nop' - operands = tuple() - - def encode(self): - return bytes() - - def __repr__(self): - return 'NOP' - - -# Memory related - -class LS_imm5_base(ArmInstruction): - """ ??? Rt, [Rn, imm5] """ - operands = (Reg8Op, MemR8Rel) - def __init__(self, rt, memop): - assert memop.offset % 4 == 0 - self.imm5 = memop.offset >> 2 - self.rn = memop.basereg.num - self.rt = rt - self.memloc = memop - assert self.rn < 8 - assert self.rt.num < 8 - - def encode(self): - Rn = self.rn - Rt = self.rt.num - imm5 = self.imm5 - - h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt - return u16(h) - - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc) - - -@armtarget.instruction -class storeimm5_ins(LS_imm5_base): - mnemonic = 'STR' - opcode = 0xC - - @classmethod - def fromim(cls, im): - mem = MemR8Rel(im.src[0], im.others[0]) - return cls(im.src[1], mem) - - -@armtarget.instruction -class loadimm5_ins(LS_imm5_base): - mnemonic = 'LDR' - opcode = 0xD - - @classmethod - def fromim(cls, im): - mem = MemR8Rel(im.src[0], im.others[0]) - return cls(im.dst[0], mem) - -class ls_sp_base_imm8(ArmInstruction): - operands = (Reg8Op, MemSpRel) - def __init__(self, rt, memop): - self.rt = rt - self.offset = memop.offset - - def encode(self): - rt = self.rt.num - assert rt < 8 - imm8 = self.offset >> 2 - assert imm8 < 256 - h = (self.opcode << 8) | (rt << 8) | imm8 - return u16(h) - - def __repr__(self): - return '{} {}, [sp,#{}]'.format(self.mnemonic, self.rt, self.offset) - -def align(x, m): - while ((x % m) != 0): - x = x + 1 - return x - - -@armtarget.instruction -class ldr_pcrel(ArmInstruction): - """ ldr Rt, LABEL, load value from pc relative position """ - mnemonic = 'ldr' - operands = (Reg8Op, LabelRef) - def __init__(self, rt, label): - assert isinstance(label, LabelRef) - self.rt = rt - self.label = label - self.offset = 0 - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.others[0]) - - def resolve(self, f): - la = f(self.label.name) - sa = align(self.address + 2, 4) - self.offset = (la - sa) - if self.offset < 0: - self.offset = 0 - - def encode(self): - rt = self.rt.num - assert rt < 8 - assert self.offset % 4 == 0 - imm8 = self.offset >> 2 - assert imm8 < 256 - assert imm8 >= 0 - h = (0x9 << 11) | (rt << 8) | imm8 - return u16(h) - - def __repr__(self): - return 'LDR {}, {}'.format(self.rt, self.label.name) - - -@armtarget.instruction -class ldr_sprel(ls_sp_base_imm8): - """ ldr Rt, [SP, imm8] """ - mnemonic = 'LDR' - opcode = 0x98 - - -@armtarget.instruction -class str_sprel(ls_sp_base_imm8): - """ str Rt, [SP, imm8] """ - mnemonic = 'STR' - opcode = 0x90 +# TODO: make a difference between armv7 and armv5? -@armtarget.instruction -class mov_imm8_ins(ArmInstruction): - """ mov Rd, imm8, move immediate value into register """ - mnemonic = 'mov' - opcode = 4 # 00100 Rd(3) imm8 - operands = (Reg8Op, Imm8) - def __init__(self, rd, imm): - if type(imm) is int: - imm = Imm8(imm) - assert type(imm) is Imm8 - self.imm = imm.imm - assert type(rd) is Reg8Op, str(type(rd)) - self.rd = rd - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.others[0]) - - def encode(self): - rd = self.rd.num - opcode = self.opcode - imm8 = self.imm - h = (opcode << 11) | (rd << 8) | imm8 - return u16(h) - - def __repr__(self): - return 'MOV {}, {}'.format(self.rd, self.imm) - - - -# Arithmatics: - - - -class regregimm3_base(ArmInstruction): - operands = (Reg8Op, Reg8Op, Imm3) - def __init__(self, rd, rn, imm3): - self.rd = rd - self.rn = rn - assert type(imm3) is Imm3 - self.imm3 = imm3 - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.others[0]) - - def encode(self): - rd = self.rd.num - rn = self.rn.num - imm3 = self.imm3.imm - opcode = self.opcode - h = (self.opcode << 9) | (imm3 << 6) | (rn << 3) | rd - return u16(h) - - def __repr__(self): - return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm3.imm) - -@armtarget.instruction -class addregregimm3_ins(regregimm3_base): - """ add Rd, Rn, imm3 """ - mnemonic = 'add' - opcode = 0b0001110 - - -@armtarget.instruction -class subregregimm3_ins(regregimm3_base): - """ sub Rd, Rn, imm3 """ - mnemonic = 'sub' - opcode = 0b0001111 - - -class regregreg_base(ArmInstruction): - """ ??? Rd, Rn, Rm """ - operands = (Reg8Op, Reg8Op, Reg8Op) - def __init__(self, rd, rn, rm): - self.rd = rd - self.rn = rn - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.src[1]) - - def encode(self): - rd = self.rd.num - rn = self.rn.num - rm = self.rm.num - h = (self.opcode << 9) | (rm << 6) | (rn << 3) | rd - return u16(h) - - def __repr__(self): - return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) - - -@armtarget.instruction -class addregs_ins(regregreg_base): - mnemonic = 'ADD' - opcode = 0b0001100 - - -@armtarget.instruction -class subregs_ins(regregreg_base): - mnemonic = 'SUB' - opcode = 0b0001101 - - - -@armtarget.instruction -class movregreg_ext_ins(ArmInstruction): - """ mov rd, rm """ - operands = (ArmRegister, ArmRegister) - mnemonic = 'MOV' - def __init__(self, rd, rm): - self.rd = rd - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0]) - - def encode(self): - Rd = self.rd.num & 0x7 - D = (self.rd.num >> 3) & 0x1 - Rm = self.rm.num - opcode = 0b01000110 - return u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd) - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) - - -@armtarget.instruction -class mulregreg_ins(ArmInstruction): - """ mul Rn, Rdm """ - operands = (Reg8Op, Reg8Op) - mnemonic = 'MUL' - def __init__(self, rn, rdm): - self.rn = rn - self.rdm = rdm - - @classmethod - def fromim(cls, im): - assert im.src[1] is im.dst[0] - return cls(im.src[0], im.dst[0]) - - def encode(self): - rn = self.rn.num - rdm = self.rdm.num - opcode = 0b0100001101 - h = (opcode << 6) | (rn << 3) | rdm - return u16(h) - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) - - -class regreg_base(ArmInstruction): - """ ??? Rdn, Rm """ - operands = (Reg8Op, Reg8Op) - # TODO: integrate with the code gen interface: - src = (0, 1) - dst = (0,) - def __init__(self, rdn, rm): - self.rdn = rdn - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.src[0], im.src[1]) - - def encode(self): - rdn = self.rdn.num - rm = self.rm.num - h = (self.opcode << 6) | (rm << 3) | rdn - return u16(h) - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm) - - -@armtarget.instruction -class movregreg_ins(regreg_base): - """ mov Rd, Rm (reg8 operands) """ - # TODO: match this: - pattern = ir.Move(ir.Temp, ir.Temp) - mnemonic = 'mov' - opcode = 0 - - -@armtarget.instruction -class andregs_ins(regreg_base): - mnemonic = 'AND' - opcode = 0b0100000000 - +class ArmTarget(Target): + def __init__(self): + super().__init__('arm') + for i in allins: + self.addInstruction(i) + # TODO: fix this nicer? + #setattr(self, i.__name__, i) + self.check() -@armtarget.instruction -class orrregs_ins(regreg_base): - mnemonic = 'ORR' - opcode = 0b0100001100 - - -@armtarget.instruction -class cmp_ins(regreg_base): - mnemonic = 'CMP' - opcode = 0b0100001010 - - -@armtarget.instruction -class lslregs_ins(regreg_base): - mnemonic = 'LSL' - opcode = 0b0100000010 - -@armtarget.instruction -class cmpregimm8_ins(ArmInstruction): - """ cmp Rn, imm8 """ - mnemonic = 'cmp' - opcode = 5 # 00101 - operands = (Reg8Op, Imm8) - def __init__(self, rn, imm): - self.rn = rn - self.imm = imm - def encode(self): - rn = self.rn.num - imm = self.imm.imm - opcode = self.opcode - h = (opcode << 11) | (rn << 8) | imm - return u16(h) - - -# Jumping: - -def wrap_negative(x, bits): - b = struct.unpack('<I', struct.pack('<i', x))[0] - mask = (1 << bits) - 1 - return b & mask - -class jumpBase_ins(ArmInstruction): - operands = (LabelRef,) - def __init__(self, target_label): - assert type(target_label) is LabelRef - self.target = target_label - self.offset = 0 - - def resolve(self, f): - la = f(self.target.name) - sa = self.address + 4 - self.offset = (la - sa) - - def __repr__(self): - return '{} {}'.format(self.mnemonic, self.target.name) - - -@armtarget.instruction -class b_ins(jumpBase_ins): - mnemonic = 'B' - def encode(self): - imm11 = wrap_negative(self.offset >> 1, 11) - h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode - return u16(h) - - -@armtarget.instruction -class bl_ins(jumpBase_ins): - mnemonic = 'BL' - def encode(self): - imm32 = wrap_negative(self.offset >> 1, 32) - imm11 = imm32 & 0x7FF - imm10 = (imm32 >> 11) & 0x3FF - j1 = 1 # TODO: what do these mean? - j2 = 1 - s = (imm32 >> 24) & 0x1 - h1 = (0b11110 << 11) | (s << 10) | imm10 - h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 - return u16(h1) + u16(h2) - - -class cond_base_ins(jumpBase_ins): - def encode(self): - imm8 = wrap_negative(self.offset >> 1, 8) - h = (0b1101 << 12) | (self.cond << 8) | imm8 - return u16(h) - - -@armtarget.instruction -class beq_ins(cond_base_ins): - mnemonic = 'beq' - cond = 0 - - -@armtarget.instruction -class bne_ins(cond_base_ins): - mnemonic = 'bne' - cond = 1 - - -@armtarget.instruction -class blt_ins(cond_base_ins): - mnemonic = 'blt' - cond = 0b1011 - - -@armtarget.instruction -class bgt_ins(cond_base_ins): - mnemonic = 'bgt' - cond = 0b1100 - - -@armtarget.instruction -class push_ins(ArmInstruction): - operands = (RegisterSet,) - mnemonic = 'push' - def __init__(self, regs): - assert (type(regs),) == self.operands, (type(regs),) - self.regs = regs - def __repr__(self): - return '{0} {{{1}}}'.format(self.mnemonic, self.regs) - def encode(self): - reg_list = 0 - M = 0 - for n in self.regs.registerNumbers(): - if n < 8: - reg_list |= (1 << n) - elif n == 14: - M = 1 - else: - raise NotImplementedError('not implemented for this register') - h = (0x5a << 9) | (M << 8) | reg_list - return u16(h) - - -@armtarget.instruction -class pop_ins(ArmInstruction): - operands = (RegisterSet,) - mnemonic = 'pop' - - def __init__(self, regs): - self.regs = regs - - def __repr__(self): - return '{0} {{{1}}}'.format(self.mnemonic, self.regs) - - def encode(self): - reg_list = 0 - P = 0 - for n in self.regs.registerNumbers(): - if n < 8: - reg_list |= (1 << n) - elif n == 15: - P = 1 - else: - raise NotImplementedError('not implemented for this register') - h = (0x5E << 9) | (P << 8) | reg_list - return u16(h) - - -@armtarget.instruction -class yield_ins(ArmInstruction): - operands = () - mnemonic = 'yield' - - def encode(self): - return u16(0xbf10) - -# misc: - -# add/sub SP: -class addspsp_base(ArmInstruction): - operands = (RegSpOp, RegSpOp, Imm7) - def __init__(self, _sp, _sp2, imm7): - self.imm7 = imm7.imm - assert self.imm7 % 4 == 0 - self.imm7 >>= 2 - - def encode(self): - return u16((self.opcode << 7) |self.imm7) - - def __repr__(self): - return '{} sp, sp, {}'.format(self.mnemonic, self.imm7 << 2) - -@armtarget.instruction -class addspsp_ins(addspsp_base): - mnemonic = 'add' - opcode = 0b101100000 - - -@armtarget.instruction -class subspsp_ins(addspsp_base): - mnemonic = 'sub' - opcode = 0b101100001 - -armtarget.check() - + def startCode(self, outs): + """ Emit some startup code in the output stream """ + outs.selectSection('code') + # assembly glue to make it work: + # TODO: this must be in source code, not in compiler + outs.emit(Dcd(Imm32(0x20000678))) # initial SP + outs.emit(Dcd(Imm32(0x08000009))) # reset vector + outs.emit(B(LabelRef('main')))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/armv7.lidl Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,16 @@ + + +instruction yield { + encoding: 0xbf10 +} + +base rrr_base { + encoding: '' +} + +instruction add : rrr_base { + semantics: { + Rd = Rm + Rn; + } +} +
--- a/python/target/basetarget.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/basetarget.py Wed Nov 27 08:06:42 2013 +0100 @@ -12,47 +12,36 @@ # standard immediates: -class Imm8: +class ImmBase: def __init__(self, imm): - assert imm < 256 + assert type(imm) is int + assert imm < self.Max() self.imm = imm @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 256: - return cls(vop.number) - -class Imm7: - def __init__(self, imm): - assert imm < 128 - self.imm = imm + def Max(cls): + return 2**cls.bits @classmethod def Create(cls, vop): - if type(vop) is ANumber and vop.number < 128: + if type(vop) is ANumber and vop.number < cls.Max(): return cls(vop.number) -class Imm3: - def __init__(self, imm): - assert imm < 8 - assert type(imm) is int - self.imm = imm + +class Imm3(ImmBase): + bits = 3 - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 8: - return cls(vop.number) + +class Imm7(ImmBase): + bits = 7 -class Imm32: - def __init__(self, imm): - assert imm < 2**32 - assert type(imm) is int - self.imm = imm + +class Imm8(ImmBase): + bits = 8 - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 2**32: - return cls(vop.number) + +class Imm32(ImmBase): + bits = 32 class LabelRef: @@ -65,9 +54,12 @@ if type(vop) is ASymbol: return cls(vop.name) + class Instruction: + """ Base instruction class """ def encode(self): raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self))) + def resolve(self, f): pass @@ -77,7 +69,6 @@ def encode(self): return bytes() - class PseudoInstruction(Instruction): pass @@ -127,6 +118,7 @@ pad.append(0) return bytes(pad) + class DebugInfo(PseudoInstruction): def __init__(self, i): self.info = i @@ -137,6 +129,7 @@ def encode(self): return bytes() + class Register(Operand): def __init__(self, name): self.name = name @@ -195,4 +188,3 @@ if all(isinstance(rop, optype) for rop, optype in zip(rops, ic.operands)): return ic(*rops) raise CompilerError('No suitable instruction found for "{0}"'.format(vi)) -
--- a/python/target/msp430.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/msp430.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,4 +1,4 @@ -from target import Register, Instruction, Target +from .basetarget import Register, Instruction, Target from asmnodes import ASymbol, ANumber from ppci import CompilerError import struct @@ -245,4 +245,3 @@ twoOpIns('bis', 13) twoOpIns('xor', 14) twoOpIns('and', 15) -
--- a/python/target/openrisc.lidl Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/openrisc.lidl Wed Nov 27 08:06:42 2013 +0100 @@ -1,5 +1,5 @@ -// Openrisc description in lidl (lcfos isa description language) +// Openrisc description in LIDL (lcfos isa description language) // Register storage: storage r {
--- a/python/usb.py Sun Nov 24 11:24:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -from ctypes import Structure, POINTER, CDLL, CFUNCTYPE -from ctypes import c_uint16, c_uint8, c_int, c_uint, c_ssize_t, c_void_p -from ctypes import byref, create_string_buffer - -# libusb wrapper: -libusb = CDLL('libusb-1.0.so') - -# helper: -def buildfunc(name, argtypes, restype=c_int): - f = getattr(libusb, name) - f.argtypes = argtypes - f.restype = restype - globals()[name] = f - return f -def enum(**enums): - reverse = dict((value, key) for key, value in enums.items()) - enums['reverse_mapping'] = reverse - return type('enum', (), enums) - -# enums -libusb_class_code = enum(PER_INTERFACE=0, AUDIO=1, COMM=2, HID=3, \ - PHYSICAL=5, PRINTER=7, PTP=6, MASS_STORAGE=8, HUB=9, \ - DATA=10, SMART_CARD=0xb, CONTENT_SECURITY=0xd, VIDEO=0xe, \ - PERSONAL_HEALTHCARE=0xf, DIAGNOSTIC_DEVICE=0xdc, WIRELESS=0xe,\ - APPLICATION=0xfe, VENDOR_SPEC=0xff) -libusb_speed = enum(UNKNOWN=0, LOW=1, FULL=2, HIGH=3, SUPER=4) -libusb_error = enum(SUCCES=0, ERROR_IO=-1, ERROR_INVALID_PARAM=-2, \ - ERROR_ACCESS=-3, ERROR_NO_DEVICE=-4, ERROR_NOT_FOUND=-5, \ - ERROR_BUSY=-6, ERROR_TIMEOUT=-7, ERROR_OVERFLOW=-8, \ - ERROR_PIPE=-9, ERROR_INTERRUPTED=-10, ERROR_NO_MEM=-11, \ - ERROR_NOT_SUPPORTED=-12, ERROR_OTHER=-99) -libusb_transfer_status = enum(\ - COMPLETED=0, ERROR=1, TIMED_OUT=2, \ - CANCELLED=3, STALL=4, NO_DEVICE=5, OVERFLOW=6) - -# types -c_int_p = POINTER(c_int) -class libusb_context(Structure): - pass -libusb_context_p = POINTER(libusb_context) -libusb_context_p_p = POINTER(libusb_context_p) - -class libusb_device(Structure): - pass -libusb_device_p = POINTER(libusb_device) -libusb_device_p_p = POINTER(libusb_device_p) -libusb_device_p_p_p = POINTER(libusb_device_p_p) - -class libusb_device_handle(Structure): - pass -libusb_device_handle_p = POINTER(libusb_device_handle) -libusb_device_handle_p_p = POINTER(libusb_device_handle_p) - -class libusb_device_descriptor(Structure): - _fields_ = [ - ('bLength', c_uint8), - ('bDescriptorType', c_uint8), - ('bcdUSB', c_uint16), - ('bDeviceClass', c_uint8), - ('bDeviceSubClass', c_uint8), - ('bDeviceProtocol', c_uint8), - ('bMaxPacketSize0', c_uint8), - ('idVendor', c_uint16), - ('idProduct', c_uint16), - ('bcdDevice', c_uint16), - ('iManufacturer', c_uint8), - ('iProduct', c_uint8), - ('iSerialNumber', c_uint8), - ('iNumConfigurations', c_uint8) - ] -libusb_device_descriptor_p = POINTER(libusb_device_descriptor) - -""" -class libusb_transfer(Structure): - pass -libusb_transfer_p = POINTER(libusb_transfer) -libusb_transfer_cb_fn = CFUNCTYPE(None, libusb_transfer_p) -libusb_transfer._fields_ = [ - ('dev_handle', libusb_device_handle_p), - ('flags', c_uint8), - ('endpoint', c_uchar), - ('type', c_uchar), - ('timeout', c_uint), - ('status', c_int), # enum libusb_transfer_status - ('length', c_int), - ('actual_length', c_int), - ('callback', libusb_transfer_cb_fn), - ('userdata', c_void_p), - ('buffer', c_void_p), - ('num_iso_packets', c_int), - ('iso_packet_desc', libusb_iso_packet_descriptor) - ] -""" -# functions -buildfunc('libusb_init', [libusb_context_p_p], c_int) - -buildfunc('libusb_get_device_list', \ - [libusb_context_p, libusb_device_p_p_p], c_ssize_t) -buildfunc('libusb_free_device_list', [libusb_device_p_p, c_int], None) -buildfunc('libusb_get_bus_number', [libusb_device_p], c_uint8) -buildfunc('libusb_get_device_address', [libusb_device_p], c_uint8) -buildfunc('libusb_get_device_speed', [libusb_device_p]) -buildfunc('libusb_unref_device', [libusb_device_p], None) -buildfunc('libusb_open', [libusb_device_p, libusb_device_handle_p_p]) -buildfunc('libusb_close', [libusb_device_handle_p], None) -buildfunc('libusb_get_configuration',[libusb_device_handle_p,POINTER(c_int)]) -buildfunc('libusb_set_configuration', [libusb_device_handle_p, c_int]) -buildfunc('libusb_claim_interface', [libusb_device_handle_p, c_int]) - -buildfunc('libusb_get_device_descriptor',\ - [libusb_device_p, libusb_device_descriptor_p]) - -# synchronous functions: -buildfunc('libusb_bulk_transfer', [libusb_device_handle_p, c_uint8, \ - c_void_p, c_int, c_int_p, c_uint]) - -# pythonic API: - -class UsbError(Exception): - def __init__(self, msg, errorcode): - if errorcode in libusb_error.reverse_mapping: - errorcode = libusb_error.reverse_mapping[errorcode] - msg = msg + 'Error code: {0}'.format(errorcode) - super().__init__(msg) - -class UsbContext(object): - """ A usb context in case of multiple use """ - def __init__(self): - self.context_p = libusb_context_p() - r = libusb_init(byref(self.context_p)) - if r != 0: - raise UsbError('libusb_init error!', r) - def getDeviceList(self): - devlist = libusb_device_p_p() - count = libusb_get_device_list(self.context_p, byref(devlist)) - if count < 0: - raise UsbError('Error getting device list', count) - l = [UsbDevice(self, device_p.contents) for device_p in devlist[0:count]] - libusb_free_device_list(devlist, 0) - return l - DeviceList = property(getDeviceList) - -class UsbDevice: - """ A detected usb device """ - def __init__(self, context, device_p): - self.context = context - self.dev_p = device_p - def __del__(self): - libusb_unref_device(self.dev_p) - def getBusNumber(self): - return libusb_get_bus_number(self.dev_p) - BusNumber = property(getBusNumber) - def getDeviceAddress(self): - return libusb_get_device_address(self.dev_p) - DeviceAddress = property(getDeviceAddress) - def getSpeed(self): - s = libusb_get_device_speed(self.dev_p) - if s in libusb_speed.reverse_mapping: - s = libusb_speed.reverse_mapping[s] - return s - Speed = property(getSpeed) - def getDescriptor(self): - descriptor = libusb_device_descriptor() - r = libusb_get_device_descriptor(self.dev_p, byref(descriptor)) - if r != 0: - raise UsbError('Error getting descriptor', r) - return descriptor - Descriptor = property(getDescriptor) - VendorId = property(lambda self: self.Descriptor.idVendor) - ProductId = property(lambda self: self.Descriptor.idProduct) - NumConfigurations = property(lambda self: self.Descriptor.bNumConfigurations) - def open(self): - """ Opens this device and returns a handle """ - handle_p = libusb_device_handle_p() - r = libusb_open(self.dev_p, byref(handle_p)) - if r != 0: - raise UsbError('error opening device', r) - return UsbDeviceHandle(self, handle_p) - def __repr__(self): - r2 = 'Usb device: bus {0} address {1} {2:04X}:{3:04X} speed {4}' \ - .format( \ - self.BusNumber, self.DeviceAddress, self.VendorId, \ - self.ProductId, self.Speed) - return r2 - -USB_ENDPOINT_DIR_MASK = 0x80 -USB_ENDPOINT_IN = 0x80 -USB_ENDPOINT_OUT = 0x0 - -class UsbDeviceHandle: - """ Handle to a detected usb device """ - def __init__(self, device, handle_p): - self.device = device - self.handle_p = handle_p - def __del__(self): - self.close() - def close(self): - if self.handle_p: - libusb_close(self.handle_p) - self.handle_p = None - def getConfiguration(self): - config = c_int() - r = libusb_get_configuration(self.handle_p, byref(config)) - if r != 0: raise UsbError('Error getting configuration', r) - return config.value - def setConfiguration(self, config): - r = libusb_set_configuration(self.handle_p, config) - if r != 0: raise UsbError('Error setting configuration', r) - Configuration = property(getConfiguration, setConfiguration) - def claimInterface(self, interface_number): - r = libusb_claim_interface(self.handle_p, interface_number) - if r != 0: raise UsbError('Error claiming interface', r) - def bulkWrite(self, endpoint, data, timeout=0): - """ Synchronous bulk write """ - assert type(data) is bytes - # assure the endpoint indicates the correct: - endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_OUT - buf = create_string_buffer(data) - transferred = c_int() - r = libusb_bulk_transfer(self.handle_p, endpoint, buf, len(data), \ - byref(transferred), timeout) - if r != 0: - raise UsbError('Bulk write failed', r) - if transferred.value != len(data): - raise UsbError('Not all {0} transferred {1}'.format(len(data), \ - transferred.value)) - def bulkRead(self, endpoint, numbytes, timeout=0): - """ Synchronous bulk read """ - # assure the endpoint indicates the correct: - endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_IN - buf = create_string_buffer(numbytes) - transferred = c_int() - r = libusb_bulk_transfer(self.handle_p, endpoint, buf, numbytes, \ - byref(transferred), timeout) - if r != 0: - raise UsbError('Bulk read failed', r) - if transferred.value != numbytes: - raise UsbError('Not all {0} transferred {1}'.format(numbytes, \ - transferred.value)) - data = buf.raw[0:numbytes] - return data - -class UsbTransfer: - def __init__(self): - libusb_alloc_transfer(0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/__init__.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,4 @@ + + +from .hexfile import HexFile, HexFileException +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/adi.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,59 @@ + +# Implementation of the ADI (ARM Debug Interface) v5 interface. + +COMPONENT_CLASSES = {0x1: 'ROM table'} + +class Adi: + def __init__(self, iface): + self.iface = iface + def r32(self, address): + return self.iface.read_debug32(address) + def w32(self, address, value): + self.iface.write_debug32(address, value) + def getId(self, offset): + print('reading id from {0:X}'.format(offset)) + pid4 = self.r32(offset + 0xFD0) + #print('pid4', pid4) + pid5 = self.r32(offset + 0xFD4) + pid6 = self.r32(offset + 0xFD8) + pid7 = self.r32(offset + 0xFDC) + pid0 = self.r32(offset + 0xFE0) + pid1 = self.r32(offset + 0xFE4) + pid2 = self.r32(offset + 0xFE8) + pid3 = self.r32(offset + 0xFEC) + cid0 = self.r32(offset + 0xFF0) + cid1 = self.r32(offset + 0xFF4) + cid2 = self.r32(offset + 0xFF8) + cid3 = self.r32(offset + 0xFFC) + pids = [pid0, pid1, pid2, pid3, pid4, pid5, pid6, pid7] + cids = [cid0, cid1, cid2, cid3] + print('cids:', [hex(x) for x in cids], 'pids', [hex(x) for x in pids]) + valid = cid0 == 0xD and (cid1 & 0xF) == 0x0 and cid2 == 0x5 and cid3 == 0xB1 + if valid: + component_class = cid1 >> 4 + else: + print('invalid class') + component_class = 0 + # TODO: use pids + return component_class, pids + + def parseRomTable(self, offset): + assert (offset & 0xFFF) == 0 + component_class, pid = self.getId(offset) + assert component_class == 1 + print('Component class:', COMPONENT_CLASSES[component_class]) + print('memory also on this bus:', self.r32(offset + 0xFCC)) + idx = 0 + entry = self.r32(offset + idx * 4) + while entry != 0: + #print('Entry: {0:X}'.format(entry)) + entryOffset = entry & 0xFFFFF000 + cls, pids = self.getId((offset + entryOffset) & 0xFFFFFFFF) + print('class:', cls) + if cls == 9: + print('Debug block found!') + + idx += 1 + entry = self.r32(offset + idx * 4) + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/devices.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,63 @@ +import sys +import usb + +# Global device list to which devices are registered. +devices = {} + +def registerDevice(chipId): + """ Decorator to register a device """ + def wrapper(dev): + devices[chipId] = dev + return dev + return wrapper + +# Global interface dictionary. +interfaces = {} + +def registerInterface(vid_pid): + def wrapper(iface): + interfaces[vid_pid] = iface + return iface + return wrapper + +def createInterfaces(): + """ Create a list of detected interfaces """ + ctx = usb.UsbContext() + + # Retrieve all usb devices: + devs = ctx.DeviceList + keys = interfaces.keys() + + # Filter function to filter only registered interfaces: + def filt(usbiface): + return (usbiface.VendorId, usbiface.ProductId) in keys + def buildInterface(usbiface): + key = (usbiface.VendorId, usbiface.ProductId) + iface = interfaces[key] + return iface(usbiface) + return [buildInterface(uif) for uif in filter(filt, devs)] + +class Device: + """ + Base class for a device possibly connected via an interface. + """ + def __init__(self, iface): + # Store the interface through which this device is connected: + assert isinstance(iface, Interface) + self.iface = iface + +class Interface: + """ + Generic interface class. Connected via Usb to a JTAG interface. + Possibly is connected with a certain chip. + """ + def createDevice(self): + """ Try to get the device connected to this interface """ + if self.ChipId in devices: + return devices[self.ChipId](self) + raise STLinkException('No device found!') + +class STLinkException(Exception): + """ Exception used for interfaces and devices """ + pass +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/hexfile.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,154 @@ +import os +import struct +import binascii + +DATA = 0 +EOF = 1 +EXTLINADR = 4 + +class HexFileException(Exception): + pass + + +def parseHexLine(line): + """ Parses a hexfile line into three parts """ + line = line[1:] # Remove ':' + nums = bytes.fromhex(line) + bytecount = nums[0] + if len(nums) != bytecount + 5: + raise HexFileException('byte count field incorrect') + crc = sum(nums) + if (crc & 0xFF) != 0: + raise HexFileException('crc incorrect') + address = struct.unpack('>H', nums[1:3])[0] + typ = nums[3] + data = nums[4:-1] + return (address, typ, data) + +def makeHexLine(address, typ, data=bytes()): + bytecount = len(data) + nums = bytearray() + nums.append(bytecount) + nums.extend(struct.pack('>H', address)) + nums.append(typ) + nums.extend(data) + crc = sum(nums) + crc = ((~crc) + 1) & 0xFF + nums.append(crc) + line = ':' + binascii.hexlify(nums).decode('ascii') + return line + +def chunks(data, csize=16): + idx = 0 + while idx < len(data): + s = min(len(data) - idx, csize) + yield data[idx:idx+s] + idx += s + +def hexfields(f): + for line in f: + line = line.strip() # Strip spaces and newlines + if not line: + continue # Skip empty lines + if line[0] != ':': + continue # Skip lines that do not start with a ':' + yield parseHexLine(line) + + +class HexFile: + """ Represents an intel hexfile """ + def __init__(self): + self.regions = [] + self.startAddress = 0 + + def load(self, f): + endOfFile = False + ext = 0 + for address, typ, data in hexfields(f): + if endOfFile: + raise HexFileException('hexfile line after end of file record') + if typ == 0x0: # Data record + self.addRegion(address + ext, data) + elif typ == EXTLINADR: # Extended linear address record + ext = (struct.unpack('>H', data[0:2])[0]) << 16 + elif typ == EOF: # End of file record + if len(data) != 0: + raise HexFileException('end of file not empty') + endOfFile = True + elif typ == 0x5: # Start address record (where IP goes after loading) + self.startAddress = struct.unpack('>I', data[0:4])[0] + else: + raise HexFileException('record type {0} not implemented'.format(typ)) + + def __repr__(self): + size = sum(len(r.data) for r in self.regions) + return 'Hexfile containing {} bytes'.format(size) + + def dump(self): + print(self) + for r in self.regions: + print(r) + + def __eq__(self, other): + regions = self.regions + oregions = other.regions + if len(regions) != len(oregions): + return False + return all(rs == ro for rs, ro in zip(regions, oregions)) + + def addRegion(self, address, data): + r = HexFileRegion(address, data) + self.regions.append(r) + self.check() + + def check(self): + self.regions.sort(key=lambda r: r.address) + change = True + while change and len(self.regions) > 1: + change = False + for r1, r2 in zip(self.regions[:-1], self.regions[1:]): + if r1.EndAddress == r2.address: + r1.addData(r2.data) + self.regions.remove(r2) + change = True + elif r1.EndAddress > r2.address: + raise HexFileException('Overlapping regions') + + def merge(self, other): + for r in other.regions: + self.addRegion(r.address, r.data) + + def save(self, f): + def emit(address, typ, data=bytes()): + print(makeHexLine(address, typ, data), file=f) + for r in self.regions: + ext = r.address & 0xFFFF0000 + emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) + address = r.address - ext + for chunk in chunks(r.data): + if address >= 0x10000: + ext += 0x10000 + emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) + address -= 0x10000 + emit(address, DATA, chunk) + address += len(chunk) + emit(0, EOF) + + +class HexFileRegion: + def __init__(self, address, data = bytes()): + self.address = address + self.data = data + + def __repr__(self): + return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data)) + + def __eq__(self, other): + return (self.address, self.data) == (other.address, other.data) + + def addData(self, d): + self.data = self.data + d + + @property + def EndAddress(self): + return self.address + len(self.data)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/lsusb.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,31 @@ +#!/usr/bin/python + +from usb import UsbContext + +# try to read usb.ids: +vids = {} +pids = {} +try: + with open('usb.ids', 'r', errors='ignore') as f: + vid = 0 + for l in f: + if l.startswith('#') or not l.strip(): + continue + if l.startswith('\t\t'): + print('iface:', l) + elif l.startswith('\t'): + print('product', l) + pid = int(l[1:5], 16) + print('product', hex(pid), l) + else: + print('vendor', l) + vid = int(l[0:4], 16) + print('vendor', hex(vid), l) + +except IOError as e: + print("Error loading usb id's: {0}".format(e)) + +context = UsbContext() +for d in context.DeviceList: + print(d) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/st-flash.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,81 @@ +#!/usr/bin/python + +import argparse, sys +import stlink, stm32 +import hexfile + +def hex2int(s): + if s.startswith('0x'): + s = s[2:] + return int(s, 16) + raise ValueError('Hexadecimal value must begin with 0x') + +parser = argparse.ArgumentParser( + description='ST-link flash utility by Windel Bouwman') +subparsers = parser.add_subparsers(title='commands', + description='possible commands', dest='command') + +readparser = subparsers.add_parser('read', help='read flash contents') +readparser.add_argument('filename', type=argparse.FileType('wb', 0)) +readparser.add_argument('address', type=hex2int) +readparser.add_argument('size', type=hex2int) + +writeparser = subparsers.add_parser('write', help='write flash contents') +writeparser.add_argument('filename', type=argparse.FileType('rb')) +writeparser.add_argument('address', type=hex2int) + +hexwriteparser = subparsers.add_parser('hexwrite', help='write hexfile to flash') +hexwriteparser.add_argument('hexfile', type=argparse.FileType('r')) + +verifyparser = subparsers.add_parser('verify', help='verify flash contents') +verifyparser.add_argument('filename', type=argparse.FileType('rb')) +verifyparser.add_argument('address', type=hex2int) + +eraseparser = subparsers.add_parser('erase', help='erase flash contents') + +args = parser.parse_args() +if not args.command: + parser.print_usage() + sys.exit(1) + +# In any command case, open a device: +stl = stlink.STLink2() +stl.open() + +# Enter the right mode: +if stl.CurrentMode == stlink.DFU_MODE: + stl.exitDfuMode() + +if stl.CurrentMode != stlink.DEBUG_MODE: + stl.enterSwdMode() + +if stl.ChipId != 0x10016413: + print('Only working on stm32f4discovery board for now.') + sys.exit(2) + +# Retrieve the connected device, if any: +dev = stl.createDevice() + +if args.command == 'read': + dev_content = dev.readFlash(args.address, args.size) + args.filename.write(dev_content) +elif args.command == 'write': + content = args.filename.read() + dev.writeFlash(args.address, content) +elif args.command == 'hexwrite': + hf = hexfile.HexFile() + hf.load(args.hexfile) + r = hf.regions[0] + dev.writeFlash(r.address, r.data) +elif args.command == 'verify': + content = args.filename.read() + dev.verifyFlash(args.address, content) +elif args.command == 'erase': + dev.eraseFlash() +else: + print('unknown command', args.command) + +stl.reset() +stl.run() +stl.exitDebugMode() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/stlink.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,367 @@ +import struct, time +from usb import UsbContext, UsbDevice +from devices import Interface, STLinkException, registerInterface +import adi + +""" + More or less copied from: + https://github.com/texane/stlink + Tracing from: + https://github.com/obe1line/stlink-trace + +""" +ST_VID, STLINK2_PID = 0x0483, 0x3748 + +def checkDevice(device): + return device.VendorId == ST_VID and device.ProductId == STLINK2_PID + +DFU_MODE, MASS_MODE, DEBUG_MODE = 0, 1, 2 + +CORE_RUNNING = 0x80 +CORE_HALTED = 0x81 + +# Commands: +GET_VERSION = 0xf1 +DEBUG_COMMAND = 0xf2 +DFU_COMMAND = 0xf3 +GET_CURRENT_MODE = 0xf5 + +# dfu commands: +DFU_EXIT = 0x7 + +# debug commands: +DEBUG_ENTER = 0x20 +DEBUG_EXIT = 0x21 +DEBUG_ENTER_SWD = 0xa3 +DEBUG_GETSTATUS = 0x01 +DEBUG_FORCEDEBUG = 0x02 +DEBUG_RESETSYS = 0x03 +DEBUG_READALLREGS = 0x04 +DEBUG_READREG = 0x5 +DEBUG_WRITEREG = 0x6 +DEBUG_READMEM_32BIT = 0x7 +DEBUG_WRITEMEM_32BIT = 0x8 +DEBUG_RUNCORE = 0x9 +DEBUG_STEPCORE = 0xa + +JTAG_WRITEDEBUG_32BIT = 0x35 +JTAG_READDEBUG_32BIT = 0x36 +TRACE_GET_BYTE_COUNT = 0x42 + +# cortex M3 +CM3_REG_CPUID = 0xE000ED00 + +@registerInterface((ST_VID, STLINK2_PID)) +class STLink2(Interface): + """ STlink2 interface implementation. """ + def __init__(self, stlink2=None): + self.devHandle = None + if not stlink2: + context = UsbContext() + stlink2s = list(filter(checkDevice, context.DeviceList)) + if not stlink2s: + raise STLinkException('Could not find an ST link 2 interface') + if len(stlink2s) > 1: + print('More then one stlink2 found, picking first one') + stlink2 = stlink2s[0] + assert isinstance(stlink2, UsbDevice) # Nifty type checking + assert checkDevice(stlink2) + self.stlink2 = stlink2 + def __del__(self): + if self.IsOpen: + if self.CurrentMode == DEBUG_MODE: + self.exitDebugMode() + self.close() + def __str__(self): + if self.IsOpen: + return 'STlink2 device version {0}'.format(self.Version) + else: + return 'STlink2 device' + def open(self): + if self.IsOpen: + return + self.devHandle = self.stlink2.open() + if self.devHandle.Configuration != 1: + self.devHandle.Configuration = 1 + self.devHandle.claimInterface(0) + + # First initialization: + if self.CurrentMode == DFU_MODE: + self.exitDfuMode() + if self.CurrentMode != DEBUG_MODE: + self.enterSwdMode() + #self.reset() + def close(self): + if self.IsOpen: + self.devHandle.close() + self.devHandle = None + @property + def IsOpen(self): + return self.devHandle != None + # modes: + def getCurrentMode(self): + cmd = bytearray(16) + cmd[0] = GET_CURRENT_MODE + reply = self.send_recv(cmd, 2) # Expect 2 bytes back + return reply[0] + CurrentMode = property(getCurrentMode) + @property + def CurrentModeString(self): + modes = {DFU_MODE: 'dfu', MASS_MODE: 'massmode', DEBUG_MODE:'debug'} + return modes[self.CurrentMode] + def exitDfuMode(self): + cmd = bytearray(16) + cmd[0:2] = DFU_COMMAND, DFU_EXIT + self.send_recv(cmd) + def enterSwdMode(self): + cmd = bytearray(16) + cmd[0:3] = DEBUG_COMMAND, DEBUG_ENTER, DEBUG_ENTER_SWD + self.send_recv(cmd) + def exitDebugMode(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_EXIT + self.send_recv(cmd) + + def getVersion(self): + cmd = bytearray(16) + cmd[0] = GET_VERSION + data = self.send_recv(cmd, 6) # Expect 6 bytes back + # Parse 6 bytes into various versions: + b0, b1, b2, b3, b4, b5 = data + stlink_v = b0 >> 4 + jtag_v = ((b0 & 0xf) << 2) | (b1 >> 6) + swim_v = b1 & 0x3f + vid = (b3 << 8) | b2 + pid = (b5 << 8) | b4 + return 'stlink={0} jtag={1} swim={2} vid:pid={3:04X}:{4:04X}'.format(\ + stlink_v, jtag_v, swim_v, vid, pid) + Version = property(getVersion) + + @property + def ChipId(self): + return self.read_debug32(0xE0042000) + @property + def CpuId(self): + u32 = self.read_debug32(CM3_REG_CPUID) + implementer_id = (u32 >> 24) & 0x7f + variant = (u32 >> 20) & 0xf + part = (u32 >> 4) & 0xfff + revision = u32 & 0xf + return implementer_id, variant, part, revision + def getStatus(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_GETSTATUS + reply = self.send_recv(cmd, 2) + return reply[0] + Status = property(getStatus) + @property + def StatusString(self): + s = self.Status + statii = {CORE_RUNNING: 'CORE RUNNING', CORE_HALTED: 'CORE HALTED'} + if s in statii: + return statii[s] + return 'Unknown status' + + def reset(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_RESETSYS + self.send_recv(cmd, 2) + + # debug commands: + def step(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_STEPCORE + self.send_recv(cmd, 2) + def run(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_RUNCORE + self.send_recv(cmd, 2) + def halt(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_FORCEDEBUG + self.send_recv(cmd, 2) + + # Tracing: + def traceEnable(self): + self.write_debug32(0xE000EDF0, 0xA05F0003) + + # Enable TRCENA: + DEMCR = 0xE000EDFC + v = self.read_debug32(DEMCR) + v |= (1 << 24) + self.write_debug32(DEMCR, v) + + # ?? Enable write?? + self.write_debug32(0xE0002000, 0x2) # + + # DBGMCU_CR: + self.write_debug32(0xE0042004, 0x27) # Enable trace in async mode + + # TPIU config: + self.write_debug32(0xE0040004, 0x00000001) # current port size register --> 1 == port size = 1 + self.write_debug32(0xE0040010, 0x23) # random clock divider?? + self.write_debug32(0xE00400F0, 0x2) # selected pin protocol (2 == NRZ) + self.write_debug32(0xE0040304, 0x100) # continuous formatting + + # ITM config: + self.write_debug32(0xE0000FB0, 0xC5ACCE55) # Unlock write access to ITM + self.write_debug32(0xE0000F80, 0x00010005) # ITM Enable, sync enable, ATB=1 + self.write_debug32(0xE0000E00, 0xFFFFFFFF) # Enable all trace ports in ITM + self.write_debug32(0xE0000E40, 0x0000000F) # Set privilege mask for all 32 ports. + def writePort0(self, v32): + self.write_debug32(0xE0000000, v32) + def getTraceByteCount(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, 0x42 + reply = self.send_recv(cmd, 2) + return struct.unpack('<H', reply[0:2])[0] + def readTraceData(self): + bsize = self.getTraceByteCount() + if bsize > 0: + td = self.recv_ep3(bsize) + print(td) + else: + print('no trace data') + + # Helper 1 functions: + def write_debug32(self, address, value): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, JTAG_WRITEDEBUG_32BIT + cmd[2:10] = struct.pack('<II', address, value) + r = self.send_recv(cmd, 2) + def read_debug32(self, address): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, JTAG_READDEBUG_32BIT + cmd[2:6] = struct.pack('<I', address) # pack into u32 little endian + reply = self.send_recv(cmd, 8) + return struct.unpack('<I', reply[4:8])[0] + def write_reg(self, reg, value): + cmd = bytearray(16) + cmd[0:3] = DEBUG_COMMAND, DEBUG_WRITEREG, reg + cmd[3:7] = struct.pack('<I', value) + r = self.send_recv(cmd, 2) + def read_reg(self, reg): + cmd = bytearray(16) + cmd[0:3] = DEBUG_COMMAND, DEBUG_READREG, reg + reply = self.send_recv(cmd, 4) + return struct.unpack('<I', reply)[0] + def read_all_regs(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_READALLREGS + reply = self.send_recv(cmd, 84) + fmt = '<' + 'I' * 21 # unpack 21 register values + return list(struct.unpack(fmt, reply)) + def write_mem32(self, address, content): + assert len(content) % 4 == 0 + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_WRITEMEM_32BIT + cmd[2:8] = struct.pack('<IH', address, len(content)) + self.send_recv(cmd) + self.send_recv(content) + def read_mem32(self, address, length): + assert length % 4 == 0 + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_READMEM_32BIT + cmd[2:8] = struct.pack('<IH', address, length) + reply = self.send_recv(cmd, length) # expect memory back! + return reply + + # Helper 2 functions: + def send_recv(self, tx, rxsize=0): + """ Helper function that transmits and receives data in bulk mode. """ + # TODO: we could use here the non-blocking libusb api. + tx = bytes(tx) + #assert len(tx) == 16 + self.devHandle.bulkWrite(2, tx) # write to endpoint 2 + if rxsize > 0: + return self.devHandle.bulkRead(1, rxsize) # read from endpoint 1 + def recv_ep3(self, rxsize): + return self.devHandle.bulkRead(3, rxsize) + +if __name__ == '__main__': + # Test program + sl = STLink2() + sl.open() + sl.reset() + print('version:', sl.Version) + print('mode before doing anything:', sl.CurrentModeString) + if sl.CurrentMode == DFU_MODE: + sl.exitDfuMode() + sl.enterSwdMode() + print('mode after entering swd mode:', sl.CurrentModeString) + + i = sl.ChipId + print('chip id: 0x{0:X}'.format(i)) + print('cpu: {0}'.format(sl.CpuId)) + + print('status: {0}'.format(sl.StatusString)) + + # test registers: + sl.write_reg(0, 0xdeadbeef) + sl.write_reg(1, 0xcafebabe) + sl.write_reg(2, 0xc0ffee) + sl.write_reg(3, 0x1337) + sl.write_reg(5, 0x1332) + sl.write_reg(6, 0x12345) + assert sl.read_reg(3) == 0x1337 + assert sl.read_reg(5) == 0x1332 + assert sl.read_reg(6) == 0x12345 + regs = sl.read_all_regs() + for i in range(len(regs)): + print('R{0}=0x{1:X}'.format(i, regs[i])) + + print('tracing') + sl.traceEnable() + sl.run() + sl.writePort0(0x1337) # For test + time.sleep(0.1) + td = sl.readTraceData() + print('trace data:', td) + + # Test CoreSight registers: + idr4 = sl.read_debug32(0xE0041fd0) + print('idr4 =', idr4) + + print('== ADI ==') + a = adi.Adi(sl) + a.parseRomTable(0xE00FF000) # why is rom table at 0xE00FF000? + print('== ADI ==') + + # Detect ROM table: + id4 = sl.read_debug32(0xE00FFFD0) + id5 = sl.read_debug32(0xE00FFFD4) + id6 = sl.read_debug32(0xE00FFFD8) + id7 = sl.read_debug32(0xE00FFFDC) + id0 = sl.read_debug32(0xE00FFFE0) + id1 = sl.read_debug32(0xE00FFFE4) + id2 = sl.read_debug32(0xE00FFFE8) + id3 = sl.read_debug32(0xE00FFFEC) + pIDs = [id0, id1, id2, id3, id4, id5, id6, id7] + print(pIDs) + + print('reading from 0xE00FF000') + scs = sl.read_debug32(0xE00FF000) + print('scs {0:08X}'.format(scs)) + dwt = sl.read_debug32(0xE00FF004) + print('dwt {0:08X}'.format(dwt)) + fpb = sl.read_debug32(0xE00FF008) + print('fpb {0:08X}'.format(fpb)) + itm = sl.read_debug32(0xE00FF00C) + print('itm {0:08X}'.format(itm)) + tpiu = sl.read_debug32(0xE00FF010) + print('tpiu {0:08X}'.format(tpiu)) + etm = sl.read_debug32(0xE00FF014) + print('etm {0:08X}'.format(etm)) + assert sl.read_debug32(0xE00FF018) == 0x0 # end marker + + devid = sl.read_debug32(0xE0040FC8) + print('TPIU_DEVID: {0:X}'.format(devid)) + devtype = sl.read_debug32(0xE0040FCC) + print('TPIU_TYPEID: {0:X}'.format(devtype)) + + sl.exitDebugMode() + print('mode at end:', sl.CurrentModeString) + + sl.close() + print('Test succes!') +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/stm32.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,264 @@ +import time +import logging +from devices import Device, registerDevice, STLinkException, Interface +import stlink + +# F4 specifics: +STM32_FLASH_BASE = 0x08000000 +STM32_SRAM_BASE = 0x20000000 + +# flash registers: +FLASH_F4_REGS_ADDR = 0x40023c00 +FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04 +FLASH_F4_SR = FLASH_F4_REGS_ADDR + 0x0c +FLASH_F4_CR = FLASH_F4_REGS_ADDR + 0x10 + +FLASH_F4_CR_START = 16 +FLASH_F4_CR_LOCK = 31 +FLASH_CR_PG = 0 +FLASH_F4_CR_SER = 1 +FLASH_CR_MER = 2 +FLASH_F4_CR_SNB = 3 +FLASH_F4_CR_SNB_MASK = 0x38 +FLASH_F4_SR_BSY = 16 + +class Stm32F4(Device): + """ + Implementation of the specifics of the STM32F4xx device series. + """ + def __init__(self, iface): + super().__init__(iface) + self.logger = logging.getLogger('stm32') + + def __str__(self): + return 'STM32F4 device size=0x{1:X} id=0x{0:X}'.format(\ + self.UID, self.FlashSize) + + def calculate_F4_sector(self, address): + sectorstarts = [] + a = STM32_FLASH_BASE + for sectorsize in self.sectorsizes: + sectorstarts.append(a) + a += sectorsize + # linear search: + sec = 0 + while sec < len(self.sectorsizes) and address >= sectorstarts[sec]: + sec += 1 + sec -= 1 # one back. + return sec, self.sectorsizes[sec] + + def calcSectors(self, address, size): + off = 0 + sectors = [] + while off < size: + sectornum, sectorsize = self.calculate_F4_sector(address + off) + sectors.append((sectornum, sectorsize)) + off += sectorsize + return sectors + + # Device registers: + @property + def UID(self): + uid_base = 0x1FFF7A10 + uid1 = self.iface.read_debug32(uid_base) + uid2 = self.iface.read_debug32(uid_base + 0x4) + uid3 = self.iface.read_debug32(uid_base + 0x8) + return (uid3 << 64) | (uid2 << 32) | uid1 + + @property + def FlashSize(self): + f_id = self.iface.read_debug32(0x1FFF7A22) + f_id = f_id >> 16 + return f_id * 1024 + + @property + def Running(self): + return self.iface.Status == stlink.CORE_RUNNING + + # flashing commands: + def writeFlash(self, address, content): + flashsize = self.FlashSize + pagesize = min(self.sectorsizes) + + # Check address range: + if address < STM32_FLASH_BASE: + raise STLinkException('Flashing below flash start') + if address + len(content) > STM32_FLASH_BASE + flashsize: + raise STLinkException('Flashing above flash size') + if address & 1 == 1: + raise STLinkException('Unaligned flash') + if len(content) & 1 == 1: + self.logger.warning('unaligned length, padding with zero') + content += bytes([0]) + if address & (pagesize - 1) != 0: + raise STLinkException('Address not aligned with pagesize') + # erase required space + sectors = self.calcSectors(address, len(content)) + self.logger.info('erasing {0} sectors'.format(len(sectors))) + for sector, secsize in sectors: + self.logger.info('erasing sector {0} of {1} bytes'.format(sector, secsize)) + self.eraseFlashSector(sector) + # program pages: + self.unlockFlashIf() + self.writeFlashCrPsiz(2) # writes are 32 bits aligned + self.setFlashCrPg() + self.logger.info('writing {0} bytes'.format(len(content))) + offset = 0 + t1 = time.time() + while offset < len(content): + size = len(content) - offset + if size > 0x8000: + size = 0x8000 + chunk = content[offset:offset + size] + while len(chunk) % 4 != 0: + chunk = chunk + bytes([0]) + # Use simple mem32 writes: + self.iface.write_mem32(address + offset, chunk) + offset += size + self.logger.info('{}%'.format(offset*100/len(content))) + self.logger.info('Done!') + self.lockFlash() + # verfify program: + self.verifyFlash(address, content) + + def eraseFlashSector(self, sector): + self.waitFlashBusy() + self.unlockFlashIf() + self.writeFlashCrSnb(sector) + self.setFlashCrStart() + self.waitFlashBusy() + self.lockFlash() + + def eraseFlash(self): + self.waitFlashBusy() + self.unlockFlashIf() + self.setFlashCrMer() + self.setFlashCrStart() + self.waitFlashBusy() + self.clearFlashCrMer() + self.lockFlash() + + def verifyFlash(self, address, content): + device_content = self.readFlash(address, len(content)) + ok = content == device_content + if ok: + self.logger.info('Verify: OK') + else: + self.logger.warning('Verify: Mismatch') + + def readFlash(self, address, size): + self.logger.info('Reading {1} bytes from 0x{0:X}'.format(address, size)) + offset = 0 + tmp_size = 0x1800 + image = bytes() + while offset < size: + # Correct for last page: + if offset + tmp_size > size: + tmp_size = size - offset + + # align size to 4 bytes: + aligned_size = tmp_size + while aligned_size % 4 != 0: + aligned_size += 1 + + mem = self.iface.read_mem32(address + offset, aligned_size) + image += mem[:tmp_size] + + # indicate progress: + self.logger.info('{}%'.format(100*len(image) / size)) + + # increase for next piece: + offset += tmp_size + assert size == len(image) + self.logger.info('Done!') + return image + + def waitFlashBusy(self): + """ block until flash operation completes. """ + while self.isFlashBusy(): + time.sleep(0.01) + + def isFlashLocked(self): + mask = 1 << FLASH_F4_CR_LOCK + return self.Cr & mask == mask + + def unlockFlashIf(self): + FLASH_KEY1, FLASH_KEY2 = 0x45670123, 0xcdef89ab + if self.isFlashLocked(): + self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY1) + self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY2) + if self.isFlashLocked(): + raise STLinkException('Failed to unlock') + + def lockFlash(self): + self.Cr = self.Cr | (1 << FLASH_F4_CR_LOCK) + + def readFlashSr(self): + return self.iface.read_debug32(FLASH_F4_SR) + + def readFlashCr(self): + return self.iface.read_debug32(FLASH_F4_CR) + + def writeFlashCr(self, x): + self.iface.write_debug32(FLASH_F4_CR, x) + + Cr = property(readFlashCr, writeFlashCr) + + def writeFlashCrSnb(self, sector): + x = self.Cr + x &= ~FLASH_F4_CR_SNB_MASK + x |= sector << FLASH_F4_CR_SNB + x |= 1 << FLASH_F4_CR_SER + self.Cr = x + + def setFlashCrMer(self): + self.Cr = self.Cr | (1 << FLASH_CR_MER) + + def setFlashCrPg(self): + self.Cr = self.Cr | (1 << FLASH_CR_PG) + + def writeFlashCrPsiz(self, n): + x = self.Cr + x &= (0x3 << 8) + x |= n << 8 + self.Cr = x + + def clearFlashCrMer(self): + x = self.Cr + x &= ~(1 << FLASH_CR_MER) + self.Cr = x + + def setFlashCrStart(self): + self.Cr = self.Cr | (1 << FLASH_F4_CR_START) + + def isFlashBusy(self): + mask = 1 << FLASH_F4_SR_BSY + sr = self.readFlashSr() + # Check for error bits: + errorbits = {} + errorbits[7] = 'Programming sequence error' + errorbits[6] = 'Programming parallelism error' + errorbits[5] = 'Programming alignment error' + errorbits[4] = 'Write protection error' + errorbits[1] = 'Operation error' + #errorbits[0] = 'End of operation' + for bit, msg in errorbits.items(): + if sr & (1 << bit) == (1 << bit): + raise STLinkException(msg) + return sr & mask == mask + + +@registerDevice(0x10016413) +class Stm32F40x(Stm32F4): + """ STM32F40x and STM32F41x device series """ + def __init__(self, iface): + super().__init__(iface) + # Assert the proper size for this device: + assert self.FlashSize == 0x100000 + """ + from 0x8000000 to 0x80FFFFF + 4 sectors of 0x4000 (16 kB) + 1 sector of 0x10000 (64 kB) + 7 of 0x20000 (128 kB) + """ + self.sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/usb.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,245 @@ +from ctypes import Structure, POINTER, CDLL, CFUNCTYPE +from ctypes import c_uint16, c_uint8, c_int, c_uint, c_ssize_t, c_void_p +from ctypes import byref, create_string_buffer + +# libusb wrapper: +libusb = CDLL('libusb-1.0.so') + +# helper: +def buildfunc(name, argtypes, restype=c_int): + f = getattr(libusb, name) + f.argtypes = argtypes + f.restype = restype + globals()[name] = f + return f +def enum(**enums): + reverse = dict((value, key) for key, value in enums.items()) + enums['reverse_mapping'] = reverse + return type('enum', (), enums) + +# enums +libusb_class_code = enum(PER_INTERFACE=0, AUDIO=1, COMM=2, HID=3, \ + PHYSICAL=5, PRINTER=7, PTP=6, MASS_STORAGE=8, HUB=9, \ + DATA=10, SMART_CARD=0xb, CONTENT_SECURITY=0xd, VIDEO=0xe, \ + PERSONAL_HEALTHCARE=0xf, DIAGNOSTIC_DEVICE=0xdc, WIRELESS=0xe,\ + APPLICATION=0xfe, VENDOR_SPEC=0xff) +libusb_speed = enum(UNKNOWN=0, LOW=1, FULL=2, HIGH=3, SUPER=4) +libusb_error = enum(SUCCES=0, ERROR_IO=-1, ERROR_INVALID_PARAM=-2, \ + ERROR_ACCESS=-3, ERROR_NO_DEVICE=-4, ERROR_NOT_FOUND=-5, \ + ERROR_BUSY=-6, ERROR_TIMEOUT=-7, ERROR_OVERFLOW=-8, \ + ERROR_PIPE=-9, ERROR_INTERRUPTED=-10, ERROR_NO_MEM=-11, \ + ERROR_NOT_SUPPORTED=-12, ERROR_OTHER=-99) +libusb_transfer_status = enum(\ + COMPLETED=0, ERROR=1, TIMED_OUT=2, \ + CANCELLED=3, STALL=4, NO_DEVICE=5, OVERFLOW=6) + +# types +c_int_p = POINTER(c_int) +class libusb_context(Structure): + pass +libusb_context_p = POINTER(libusb_context) +libusb_context_p_p = POINTER(libusb_context_p) + +class libusb_device(Structure): + pass +libusb_device_p = POINTER(libusb_device) +libusb_device_p_p = POINTER(libusb_device_p) +libusb_device_p_p_p = POINTER(libusb_device_p_p) + +class libusb_device_handle(Structure): + pass +libusb_device_handle_p = POINTER(libusb_device_handle) +libusb_device_handle_p_p = POINTER(libusb_device_handle_p) + +class libusb_device_descriptor(Structure): + _fields_ = [ + ('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bcdUSB', c_uint16), + ('bDeviceClass', c_uint8), + ('bDeviceSubClass', c_uint8), + ('bDeviceProtocol', c_uint8), + ('bMaxPacketSize0', c_uint8), + ('idVendor', c_uint16), + ('idProduct', c_uint16), + ('bcdDevice', c_uint16), + ('iManufacturer', c_uint8), + ('iProduct', c_uint8), + ('iSerialNumber', c_uint8), + ('iNumConfigurations', c_uint8) + ] +libusb_device_descriptor_p = POINTER(libusb_device_descriptor) + +""" +class libusb_transfer(Structure): + pass +libusb_transfer_p = POINTER(libusb_transfer) +libusb_transfer_cb_fn = CFUNCTYPE(None, libusb_transfer_p) +libusb_transfer._fields_ = [ + ('dev_handle', libusb_device_handle_p), + ('flags', c_uint8), + ('endpoint', c_uchar), + ('type', c_uchar), + ('timeout', c_uint), + ('status', c_int), # enum libusb_transfer_status + ('length', c_int), + ('actual_length', c_int), + ('callback', libusb_transfer_cb_fn), + ('userdata', c_void_p), + ('buffer', c_void_p), + ('num_iso_packets', c_int), + ('iso_packet_desc', libusb_iso_packet_descriptor) + ] +""" +# functions +buildfunc('libusb_init', [libusb_context_p_p], c_int) + +buildfunc('libusb_get_device_list', \ + [libusb_context_p, libusb_device_p_p_p], c_ssize_t) +buildfunc('libusb_free_device_list', [libusb_device_p_p, c_int], None) +buildfunc('libusb_get_bus_number', [libusb_device_p], c_uint8) +buildfunc('libusb_get_device_address', [libusb_device_p], c_uint8) +buildfunc('libusb_get_device_speed', [libusb_device_p]) +buildfunc('libusb_unref_device', [libusb_device_p], None) +buildfunc('libusb_open', [libusb_device_p, libusb_device_handle_p_p]) +buildfunc('libusb_close', [libusb_device_handle_p], None) +buildfunc('libusb_get_configuration',[libusb_device_handle_p,POINTER(c_int)]) +buildfunc('libusb_set_configuration', [libusb_device_handle_p, c_int]) +buildfunc('libusb_claim_interface', [libusb_device_handle_p, c_int]) + +buildfunc('libusb_get_device_descriptor',\ + [libusb_device_p, libusb_device_descriptor_p]) + +# synchronous functions: +buildfunc('libusb_bulk_transfer', [libusb_device_handle_p, c_uint8, \ + c_void_p, c_int, c_int_p, c_uint]) + +# pythonic API: + +class UsbError(Exception): + def __init__(self, msg, errorcode): + if errorcode in libusb_error.reverse_mapping: + errorcode = libusb_error.reverse_mapping[errorcode] + msg = msg + 'Error code: {0}'.format(errorcode) + super().__init__(msg) + +class UsbContext(object): + """ A usb context in case of multiple use """ + def __init__(self): + self.context_p = libusb_context_p() + r = libusb_init(byref(self.context_p)) + if r != 0: + raise UsbError('libusb_init error!', r) + def getDeviceList(self): + devlist = libusb_device_p_p() + count = libusb_get_device_list(self.context_p, byref(devlist)) + if count < 0: + raise UsbError('Error getting device list', count) + l = [UsbDevice(self, device_p.contents) for device_p in devlist[0:count]] + libusb_free_device_list(devlist, 0) + return l + DeviceList = property(getDeviceList) + +class UsbDevice: + """ A detected usb device """ + def __init__(self, context, device_p): + self.context = context + self.dev_p = device_p + def __del__(self): + libusb_unref_device(self.dev_p) + def getBusNumber(self): + return libusb_get_bus_number(self.dev_p) + BusNumber = property(getBusNumber) + def getDeviceAddress(self): + return libusb_get_device_address(self.dev_p) + DeviceAddress = property(getDeviceAddress) + def getSpeed(self): + s = libusb_get_device_speed(self.dev_p) + if s in libusb_speed.reverse_mapping: + s = libusb_speed.reverse_mapping[s] + return s + Speed = property(getSpeed) + def getDescriptor(self): + descriptor = libusb_device_descriptor() + r = libusb_get_device_descriptor(self.dev_p, byref(descriptor)) + if r != 0: + raise UsbError('Error getting descriptor', r) + return descriptor + Descriptor = property(getDescriptor) + VendorId = property(lambda self: self.Descriptor.idVendor) + ProductId = property(lambda self: self.Descriptor.idProduct) + NumConfigurations = property(lambda self: self.Descriptor.bNumConfigurations) + def open(self): + """ Opens this device and returns a handle """ + handle_p = libusb_device_handle_p() + r = libusb_open(self.dev_p, byref(handle_p)) + if r != 0: + raise UsbError('error opening device', r) + return UsbDeviceHandle(self, handle_p) + def __repr__(self): + r2 = 'Usb device: bus {0} address {1} {2:04X}:{3:04X} speed {4}' \ + .format( \ + self.BusNumber, self.DeviceAddress, self.VendorId, \ + self.ProductId, self.Speed) + return r2 + +USB_ENDPOINT_DIR_MASK = 0x80 +USB_ENDPOINT_IN = 0x80 +USB_ENDPOINT_OUT = 0x0 + +class UsbDeviceHandle: + """ Handle to a detected usb device """ + def __init__(self, device, handle_p): + self.device = device + self.handle_p = handle_p + def __del__(self): + self.close() + def close(self): + if self.handle_p: + libusb_close(self.handle_p) + self.handle_p = None + def getConfiguration(self): + config = c_int() + r = libusb_get_configuration(self.handle_p, byref(config)) + if r != 0: raise UsbError('Error getting configuration', r) + return config.value + def setConfiguration(self, config): + r = libusb_set_configuration(self.handle_p, config) + if r != 0: raise UsbError('Error setting configuration', r) + Configuration = property(getConfiguration, setConfiguration) + def claimInterface(self, interface_number): + r = libusb_claim_interface(self.handle_p, interface_number) + if r != 0: raise UsbError('Error claiming interface', r) + def bulkWrite(self, endpoint, data, timeout=0): + """ Synchronous bulk write """ + assert type(data) is bytes + # assure the endpoint indicates the correct: + endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_OUT + buf = create_string_buffer(data) + transferred = c_int() + r = libusb_bulk_transfer(self.handle_p, endpoint, buf, len(data), \ + byref(transferred), timeout) + if r != 0: + raise UsbError('Bulk write failed', r) + if transferred.value != len(data): + raise UsbError('Not all {0} transferred {1}'.format(len(data), \ + transferred.value)) + def bulkRead(self, endpoint, numbytes, timeout=0): + """ Synchronous bulk read """ + # assure the endpoint indicates the correct: + endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_IN + buf = create_string_buffer(numbytes) + transferred = c_int() + r = libusb_bulk_transfer(self.handle_p, endpoint, buf, numbytes, \ + byref(transferred), timeout) + if r != 0: + raise UsbError('Bulk read failed', r) + if transferred.value != numbytes: + raise UsbError('Not all {0} transferred {1}'.format(numbytes, \ + transferred.value)) + data = buf.raw[0:numbytes] + return data + +class UsbTransfer: + def __init__(self): + libusb_alloc_transfer(0)
--- a/python/zcc.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/zcc.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import sys import argparse @@ -8,7 +8,7 @@ import ppci import codegen import outstream -import hexfile +from utils import HexFile import target @@ -23,7 +23,8 @@ target_list = [target.armtarget] -targetnames = {t.name: t for t in target_list} +targets = {t.name: t for t in target_list} +targetnames = list(targets.keys()) # Parse arguments: parser = argparse.ArgumentParser(description='lcfos Compiler') @@ -37,14 +38,14 @@ parser.add_argument('--dumpasm', action='store_true', help="Dump ASM-code") parser.add_argument('--optimize', action='store_true', help="Optimize") parser.add_argument('--target', help="Backend selection", - choices=targetnames.keys()) + choices=targetnames, required=True) parser.add_argument('-o', '--output', help='Output file', metavar='filename') parser.add_argument('--hexfile', help='Output hexfile', type=argparse.FileType('w')) parser.add_argument('--log', help='Log level (INFO,DEBUG)', type=logLevel) -def zcc(srcs, imps, outs, diag, dumpir=False): +def zcc(srcs, imps, tg, outs, diag, dumpir=False): """ Compile sources into output stream. Sources is an iterable of open files. @@ -52,9 +53,14 @@ logging.info('Zcc started') # Front end: c3b = c3.Builder(diag) - tg = target.armtarget.armtarget - # TODO select target here! - cg = codegen.CodeGenerator(outs, tg) + cg = codegen.CodeGenerator(tg) + + # TODO: remove this arm specifics: + outs.getSection('code').address = 0x08000000 + outs.getSection('data').address = 0x20000000 + + # Emit some custom start code: + tg.startCode(outs) for ircode in c3b.build(srcs, imps): if not ircode: return @@ -65,7 +71,10 @@ ircode.dump() # Code generation: - cg.generate(ircode) + cg.generate(ircode, outs) + # TODO: fixup references, do this in another way? + outs.backpatch() + outs.backpatch() # Why two times? return c3b.ok @@ -73,11 +82,11 @@ logging.basicConfig(format=logformat, level=args.log) src = args.source imps = args.imp + tg = targets[args.target] diag = ppci.DiagnosticsManager() outs = outstream.TextOutputStream() - # Invoke compiler: - res = zcc(src, imps, outs, diag, dumpir=args.dumpir) + res = zcc(src, imps, tg, outs, diag, dumpir=args.dumpir) if not res: diag.printErrors(src) return 1 @@ -93,7 +102,7 @@ if args.hexfile: logging.info('Creating hexfile') - hf = hexfile.HexFile() + hf = HexFile() hf.addRegion(0x08000000, code_bytes) hf.save(args.hexfile) return 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testarmasm.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,149 @@ +import unittest +import outstream +from asm import Assembler +from testasm import AsmTestCaseBase +from target import armtarget + + +class AssemblerARMTestCase(AsmTestCaseBase): + def setUp(self): + self.t = armtarget + self.o = outstream.BinOutputStream() + self.o.selectSection('.text') + self.a = Assembler(target=self.t, stream=self.o) + + def testMapOperand(self): + pass + + def testMovImm8(self): + self.feed('mov r4, 100') + self.check('6424') + + @unittest.skip + def testMovExt(self): + self.feed('mov r3, sp') + self.check('') + + def testYield(self): + self.feed('yield') + self.check('10bf') + + def testPush(self): + self.feed('push {r2,r3,lr}') + self.check('0cb5') + + def testPop(self): + self.feed('pop {r4-r6, pc}') + self.check('70bd') + + def testStr5(self): + self.feed('str r4, [r1 + 0]') + self.check('0c60') + + def testLdr5(self): + self.feed('ldr r4, [r0 + 0]') + self.check('0468') + + def testLdrSpRel(self): + self.feed('ldr r0, [sp + 4]') + self.check('0198') + + def testStrSpRel(self): + self.feed('str r0, [sp + 4]') + self.check('0190') + + def testLdrPcRel(self): + self.feed('ldr r7, henkie') + self.feed('ldr r6, henkie') + self.feed('ldr r1, henkie') + self.feed('align 4') + self.feed('dcd 1') + self.feed('henkie: dcd 2') + self.check('024F024E 01490000 01000000 02000000') + + def testBranch(self): + self.feed('start: b henkie') + self.feed('beq henkie') + self.feed('bne henkie') + self.feed('henkie: b start') + self.feed('eof: b eof') + self.check('01e000d0 ffd1fbe7 fee7') + + def testConditions(self): + self.feed('blt x') + self.feed('bgt x') + self.feed('x:') + self.check('00dbffdc') + + def testBoff(self): + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.feed('henkie:') + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.feed('b henkie') + self.check('05e004e0 03e002e0 01e000e0 ffe7fee7 fde7fce7 fbe7') + + def testBl(self): + self.feed('bl henkie') + self.feed('bl henkie') + self.feed('henkie:') + self.feed('bl henkie') + self.feed('bl henkie') + self.check('00f0 02f8 00f0 00f8 fff7 feff fff7 fcff') + + def testCmpRegReg(self): + self.feed('cmp r0, r1') + self.check('8842') + + def testAddimm3(self): + self.feed('add r3, r5, 2') + self.feed('add r4, r1, 6') + self.check('ab1c8c1d') + + def testSubImm3(self): + self.feed('sub r3, r5, 2') + self.feed('sub r4, r1, 6') + self.check('ab1e8c1f') + + def testLeftShift(self): + self.feed('lsl r3, r5') + self.check('ab40') + + def testAddSp(self): + self.feed('add sp,sp,8') + self.feed('add sp,sp,16') + self.check('02b004b0') + + def testSubSp(self): + self.feed('sub sp,sp,32') + self.feed('sub sp,sp,4') + self.check('88b081b0') + + def testSequence1(self): + self.feed('mov r5, 3') + self.feed('add r4, r5, 0') + self.feed('loop: add r6, r4, 7') + self.feed('cmp r6, 5') + self.check('0325 2c1c e61d 052e') + + def testSequence2(self): + self.feed('henkie:') + self.feed('push {r1,r4,r5}') + self.feed('add r5, r2, r4') + self.feed('cmp r4, r2') + self.feed('ldr r0, [sp + 4]') + self.feed('str r3, [sp + 16]') + self.feed('pop {r1, r4, r5}') + self.feed('lsl r3, r4') + self.feed('cmp r3, r5') + self.feed('beq henkie') + self.feed('bne henkie') + self.feed('b henkie') + self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7')
--- a/test/testasm.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testasm.py Wed Nov 27 08:06:42 2013 +0100 @@ -4,7 +4,6 @@ from ppci import CompilerError from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber from asm import tokenize, Assembler -import target.armtarget as arm import outstream from target import Label @@ -83,25 +82,13 @@ # A line can be empty self.a.parse_line('') + class AssemblerOtherTestCase(unittest.TestCase): def testWithoutTarget(self): a = Assembler() with self.assertRaises(CompilerError): a.assemble_line('') - @unittest.skip - def testX86(self): - testsrc = """ ; tst - begin: - mov rax, rbx ; 0x48, 0x89, 0xd8 - xor rcx, rbx ; 0x48, 0x31, 0xd9 - inc rcx ; 0x48 0xff 0xc1 - """ - a = Assembler() - a.assemble(testsrc) - # Compare with nasm output: - nasmbytes = [0x48, 0x89, 0xd8, 0x48, 0x31, 0xd9, 0x48, 0xff, 0xc1] - class OustreamTestCase(unittest.TestCase): def test1(self): @@ -112,6 +99,7 @@ class AsmTestCaseBase(unittest.TestCase): + """ Base testcase for assembly """ def feed(self, line): self.a.assemble(line) @@ -119,199 +107,5 @@ self.assertSequenceEqual(bytes.fromhex(hexstr), self.o.Data) -class AssemblerMSP430TestCase(AsmTestCaseBase): - def setUp(self): - self.t = msp430.msp430target - self.o = outstream.BinOutputStream() - self.o.selectSection('.text') - self.a = Assembler(target=self.t, stream=self.o) - - def testMapMovInstruction(self): - i = AInstruction('mov', [ASymbol('r14'), ASymbol('r15')]) - ri = self.t.mapInstruction(i) - - def testMapRetiInstruction(self): - i = AInstruction('reti', []) - ri = self.t.mapInstruction(i) - - @unittest.skip - def testMapOperand(self): - o = ASymbol('r14') - mo = self.t.mapOperand(o) - self.assertEqual(mo, msp430.r14) - - @unittest.skip - def testMapOperandIndirection(self): - o = AUnop('[]', ASymbol('r14')) - mo = self.t.mapOperand(o) - - def testMov(self): - line1 = "mov r14, r15" - self.feed(line1) - self.check('0F4E') - - def testMov1337(self): - line1 = "mov 0x1337, r12" - self.feed(line1) - self.check('3C403713') - - def testAdd(self): - line1 = "add r15, r13" - self.feed(line1) - self.check('0D5F') - - def testReti(self): - line1 = "reti" - self.feed(line1) - self.check('0013') - - def testMSPinstructionCount(self): - """ Check that there are 27 instructions """ - self.assertEqual(27, len(self.t.instructions)) - - -class AssemblerARMTestCase(AsmTestCaseBase): - def setUp(self): - self.t = arm.armtarget - self.o = outstream.BinOutputStream() - self.o.selectSection('.text') - self.a = Assembler(target=self.t, stream=self.o) - - def testMapOperand(self): - pass - - def testMovImm8(self): - self.feed('mov r4, 100') - self.check('6424') - - @unittest.skip - def testMovExt(self): - self.feed('mov r3, sp') - self.check('') - - def testYield(self): - self.feed('yield') - self.check('10bf') - - def testPush(self): - self.feed('push {r2,r3,lr}') - self.check('0cb5') - - def testPop(self): - self.feed('pop {r4-r6, pc}') - self.check('70bd') - - def testStr5(self): - self.feed('str r4, [r1 + 0]') - self.check('0c60') - - def testLdr5(self): - self.feed('ldr r4, [r0 + 0]') - self.check('0468') - - def testLdrSpRel(self): - self.feed('ldr r0, [sp + 4]') - self.check('0198') - - def testStrSpRel(self): - self.feed('str r0, [sp + 4]') - self.check('0190') - - def testLdrPcRel(self): - self.feed('ldr r7, henkie') - self.feed('ldr r6, henkie') - self.feed('ldr r1, henkie') - self.feed('align 4') - self.feed('dcd 1') - self.feed('henkie: dcd 2') - self.check('024F024E 01490000 01000000 02000000') - - def testBranch(self): - self.feed('start: b henkie') - self.feed('beq henkie') - self.feed('bne henkie') - self.feed('henkie: b start') - self.feed('eof: b eof') - self.check('01e000d0 ffd1fbe7 fee7') - - def testConditions(self): - self.feed('blt x') - self.feed('bgt x') - self.feed('x:') - self.check('00dbffdc') - - def testBoff(self): - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.feed('henkie:') - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.feed('b henkie') - self.check('05e004e0 03e002e0 01e000e0 ffe7fee7 fde7fce7 fbe7') - - def testBl(self): - self.feed('bl henkie') - self.feed('bl henkie') - self.feed('henkie:') - self.feed('bl henkie') - self.feed('bl henkie') - self.check('00f0 02f8 00f0 00f8 fff7 feff fff7 fcff') - - def testCmpRegReg(self): - self.feed('cmp r0, r1') - self.check('8842') - - def testAddimm3(self): - self.feed('add r3, r5, 2') - self.feed('add r4, r1, 6') - self.check('ab1c8c1d') - - def testSubImm3(self): - self.feed('sub r3, r5, 2') - self.feed('sub r4, r1, 6') - self.check('ab1e8c1f') - - def testLeftShift(self): - self.feed('lsl r3, r5') - self.check('ab40') - - def testAddSp(self): - self.feed('add sp,sp,8') - self.feed('add sp,sp,16') - self.check('02b004b0') - - def testSubSp(self): - self.feed('sub sp,sp,32') - self.feed('sub sp,sp,4') - self.check('88b081b0') - - def testSequence1(self): - self.feed('mov r5, 3') - self.feed('add r4, r5, 0') - self.feed('loop: add r6, r4, 7') - self.feed('cmp r6, 5') - self.check('0325 2c1c e61d 052e') - - def testSequence2(self): - self.feed('henkie:') - self.feed('push {r1,r4,r5}') - self.feed('add r5, r2, r4') - self.feed('cmp r4, r2') - self.feed('ldr r0, [sp + 4]') - self.feed('str r3, [sp + 16]') - self.feed('pop {r1, r4, r5}') - self.feed('lsl r3, r4') - self.feed('cmp r3, r5') - self.feed('beq henkie') - self.feed('bne henkie') - self.feed('b henkie') - self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7') - if __name__ == '__main__': unittest.main()
--- a/test/testc3.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testc3.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,7 +1,6 @@ import c3 import time import ppci -import x86 import ir import unittest import glob
--- a/test/testcg.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testcg.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,7 +1,8 @@ import unittest -import ppci, codegen, ir -import cortexm3 as arm -import codegenarm +import ppci +from codegen import CodeGenerator +import ir +from target import armtarget import outstream @@ -14,26 +15,27 @@ class testCodeGeneration(unittest.TestCase): def setUp(self): - self.cg = codegen.CodeGenerator(arm.armtarget) + self.cg = CodeGenerator(armtarget) def testFunction(self): + s = outstream.OutputStream() m, f, bb = genTestFunction() - bb.addInstruction(ir.Const(123)) + bb.addInstruction(ir.Exp(ir.Const(123))) bb.addInstruction(ir.Jump(f.epiloog)) m.check() - obj = self.cg.generate(m) + obj = self.cg.generate(m, s) self.assertTrue(obj) class testArmCodeGeneration(unittest.TestCase): def testStack(self): s = outstream.OutputStream() - cg = codegenarm.ArmCodeGenerator(s) + cg = CodeGenerator(armtarget) m, f, bb = genTestFunction() bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22))) bb.addInstruction(ir.Jump(f.epiloog)) m.check() - cg.generate(m) + cg.generate(m, s) #s.dump()
--- a/test/testhexfile.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testhexfile.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,6 +1,6 @@ import unittest import io -from hexfile import HexFile, HexFileException +from utils import HexFile, HexFileException class testHexFile(unittest.TestCase): @@ -38,6 +38,15 @@ hf.addRegion(0xF003, bytes.fromhex('ab')*0x10000) self.saveload(hf) + def testTwoRegions(self): + hf = HexFile() + hf2 = HexFile() + hf.addRegion(0x100, bytes.fromhex('abcd')) + hf.addRegion(0x200, bytes.fromhex('beef')) + hf2.addRegion(0x200, bytes.fromhex('beef')) + hf2.addRegion(0x100, bytes.fromhex('abcd')) + self.assertEqual(hf, hf2) + def testMerge(self): hf = HexFile() hf.addRegion(0x10, bytes.fromhex('abcdab')) @@ -74,9 +83,7 @@ def testLoad(self): hf = HexFile() - dummyhex = """ - :01400000aa15 - """ + dummyhex = """:01400000aa15""" f = io.StringIO(dummyhex) hf.load(f) self.assertEqual(1, len(hf.regions)) @@ -99,4 +106,3 @@ if __name__ == '__main__': unittest.main() -
--- a/test/testir.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testir.py Wed Nov 27 08:06:42 2013 +0100 @@ -2,7 +2,8 @@ import sys import c3 import ppci -import ir, x86, transform +import ir +import transform import optimize @@ -129,34 +130,5 @@ """ if __name__ == '__main__': - #unittest.main() - #sys.exit() - diag = ppci.DiagnosticsManager() - builder = c3.Builder(diag) - cgenx86 = x86.X86CodeGenSimple(diag) - ir = builder.build(testsrc) - diag.printErrors(testsrc) - ir.check() - ir.dump() - optimize.optimize(ir) - print('dump IR') - print('dump IR') - print('dump IR') - print('dump IR') - ir.dump() - - # Dump a graphiz file: - with open('graaf.gv', 'w') as f: - ir.dumpgv(f) - os.system('dot -Tsvg -ograaf.svg graaf.gv') - + unittest.main() sys.exit() - asm = cgenx86.genBin(ir) - #for a in asm: - # print(a) - with open('out.asm', 'w') as f: - f.write('BITS 64\n') - for a in asm: - f.write(str(a) + '\n') - print(a) -
--- a/test/testmsp430asm.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testmsp430asm.py Wed Nov 27 08:06:42 2013 +0100 @@ -3,15 +3,14 @@ import unittest from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber from asm import tokenize, Assembler -import msp430 import outstream -from target import Label +from target import Label, msp430target from testasm import AsmTestCaseBase class AssemblerMSP430TestCase(AsmTestCaseBase): def setUp(self): - self.t = msp430.msp430target + self.t = msp430target self.o = outstream.BinOutputStream() self.o.selectSection('.text') self.a = Assembler(target=self.t, stream=self.o)
--- a/test/testx86asm.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testx86asm.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,18 +1,27 @@ #!/usr/bin/python import unittest +from testasm import AsmTestCaseBase -class AssemblerTestCase(unittest.TestCase): - """ +class AssemblerTestCase(AsmTestCaseBase): + """ test methods start with 'test*' Checks several assembly constructs agains their bytecodes - """ - def setUp(self): + """ + def setUp(self): self.skipTest('not implemented yet') self.assembler = Assembler('x86-64') + a = Assembler() - def tstAssembler(self): + @unittest.skip + def testX86(self): + self.feed('mov rax, rbx') # ; 0x48, 0x89, 0xd8 + self.feed('xor rcx, rbx') # ; 0x48, 0x31, 0xd9 + self.feed('inc rcx') # ; 0x48 0xff 0xc1 + self.check('48 89 d8 48 31 d9 48 ff c1') + + def tstAssembler(self): """ Check all kind of assembler cases """ assert(assembler.shortjump(5) == [0xeb, 0x5]) assert(assembler.shortjump(-2) == [0xeb, 0xfc]) @@ -21,35 +30,43 @@ assert(assembler.nearjump(-2) == [0xe9, 0xf9, 0xff,0xff,0xff]) assert(assembler.nearjump(10,'LE') == [0x0f, 0x8e, 0xa,0x0,0x0,0x0]) - def testCall(self): - assert(assembler.call('r10') == [0x41, 0xff, 0xd2]) - assert(assembler.call('rcx') == [0xff, 0xd1]) + def testCall(self): + self.feed('call r10') + self.check('') + self.feed('call rcx') + + # assert(assembler.call('r10') == [0x41, 0xff, 0xd2]) + # assert(assembler.call('rcx') == [0xff, 0xd1]) - def testXOR(self): + def testXOR(self): assert(assembler.xorreg64('rax', 'rax') == [0x48, 0x31, 0xc0]) assert(assembler.xorreg64('r9', 'r8') == [0x4d, 0x31, 0xc1]) assert(assembler.xorreg64('rbx', 'r11') == [0x4c, 0x31, 0xdb]) - def testINC(self): + def testINC(self): assert(assembler.increg64('r11') == [0x49, 0xff, 0xc3]) assert(assembler.increg64('rcx') == [0x48, 0xff, 0xc1]) - def testPush(self): + def testPush(self): assert(assembler.push('rbp') == [0x55]) assert(assembler.push('rbx') == [0x53]) assert(assembler.push('r12') == [0x41, 0x54]) - def testPop(self): - assert(assembler.pop('rbx') == [0x5b]) - assert(assembler.pop('rbp') == [0x5d]) - assert(assembler.pop('r12') == [0x41, 0x5c]) - def testAsmLoads(self): + def testPop(self): + self.feed('pop rbx') + self.feed('pop rbp') + self.feed('pop r12') + assert(assembler.pop('rbx') == [0x5b]) + assert(assembler.pop('rbp') == [0x5d]) + assert(assembler.pop('r12') == [0x41, 0x5c]) + + def testAsmLoads(self): # TODO constant add testcases assert(assembler.mov('rbx', 'r14') == [0x4c, 0x89, 0xf3]) assert(assembler.mov('r12', 'r8') == [0x4d, 0x89, 0xc4]) assert(assembler.mov('rdi', 'rsp') == [0x48, 0x89, 0xe7]) - def testAsmMemLoads(self): + def testAsmMemLoads(self): assert(assembler.mov('rax', ['r8','r15',0x11]) == [0x4b,0x8b,0x44,0x38,0x11]) assert(assembler.mov('r13', ['rbp','rcx',0x23]) == [0x4c,0x8b,0x6c,0xd,0x23]) @@ -61,7 +78,7 @@ assert(assembler.mov('r11', ['RIP', 0xf]) == [0x4c,0x8b,0x1d,0x0f,0x0,0x0,0x0]) - def testAsmMemStores(self): + def testAsmMemStores(self): assert(assembler.mov(['rbp', 0x13],'rbx') == [0x48,0x89,0x5d,0x13]) assert(assembler.mov(['r12', 0x12],'r9') == [0x4d,0x89,0x4c,0x24,0x12]) assert(assembler.mov(['rcx', 0x11],'r14') == [0x4c,0x89,0x71,0x11]) @@ -72,27 +89,28 @@ assert(assembler.mov(['RIP', 0xf], 'r9') == [0x4c,0x89,0x0d,0x0f,0x0,0x0,0x0]) - def testAsmMOV8(self): + def testAsmMOV8(self): assert(assembler.mov(['rbp', -8], 'al') == [0x88, 0x45, 0xf8]) assert(assembler.mov(['r11', 9], 'cl') == [0x41, 0x88, 0x4b, 0x09]) assert(assembler.mov(['rbx'], 'al') == [0x88, 0x03]) assert(assembler.mov(['r11'], 'dl') == [0x41, 0x88, 0x13]) - def testAsmLea(self): + def testAsmLea(self): assert(assembler.leareg64('r11', ['RIP', 0xf]) == [0x4c,0x8d,0x1d,0x0f,0x0,0x0,0x0]) assert(assembler.leareg64('rsi', ['RIP', 0x7]) == [0x48,0x8d,0x35,0x07,0x0,0x0,0x0]) assert(assembler.leareg64('rcx', ['rbp', -8]) == [0x48,0x8d,0x4d,0xf8]) - def testAssemblerCMP(self): + def testAssemblerCMP(self): assert(assembler.cmpreg64('rdi', 'r13') == [0x4c, 0x39, 0xef]) assert(assembler.cmpreg64('rbx', 'r14') == [0x4c, 0x39, 0xf3]) assert(assembler.cmpreg64('r12', 'r9') == [0x4d, 0x39, 0xcc]) assert(assembler.cmpreg64('rdi', 1) == [0x48, 0x83, 0xff, 0x01]) assert(assembler.cmpreg64('r11', 2) == [0x49, 0x83, 0xfb, 0x02]) - def testAssemblerADD(self): + + def testAssemblerADD(self): assert(assembler.addreg64('rbx', 'r13') == [0x4c, 0x01, 0xeb]) assert(assembler.addreg64('rax', 'rbx') == [0x48, 0x01, 0xd8]) assert(assembler.addreg64('r12', 'r13') == [0x4d, 0x01, 0xec]) @@ -101,7 +119,7 @@ assert(assembler.addreg64('r11', 0x1234567) == [0x49, 0x81, 0xc3, 0x67, 0x45,0x23,0x1]) assert(assembler.addreg64('rsp', 0x33) == [0x48, 0x83, 0xc4, 0x33]) - def testAssemblerSUB(self): + def testAssemblerSUB(self): assert(assembler.subreg64('rdx', 'r14') == [0x4c, 0x29, 0xf2]) assert(assembler.subreg64('r15', 'rbx') == [0x49, 0x29, 0xdf]) assert(assembler.subreg64('r8', 'r9') == [0x4d, 0x29, 0xc8]) @@ -109,12 +127,12 @@ assert(assembler.subreg64('rsp', 0x123456) == [0x48, 0x81, 0xec, 0x56,0x34,0x12,0x0]) assert(assembler.subreg64('rsp', 0x12) == [0x48, 0x83, 0xec, 0x12]) - def testAssemblerIDIV(self): + def testAssemblerIDIV(self): assert(assembler.idivreg64('r11') == [0x49, 0xf7, 0xfb]) assert(assembler.idivreg64('rcx') == [0x48, 0xf7, 0xf9]) assert(assembler.idivreg64('rsp') == [0x48, 0xf7, 0xfc]) - def testAssemblerIMUL(self): + def testAssemblerIMUL(self): assert(assembler.imulreg64_rax('rdi') == [0x48, 0xf7, 0xef]) assert(assembler.imulreg64_rax('r10') == [0x49, 0xf7, 0xea]) assert(assembler.imulreg64_rax('rdx') == [0x48, 0xf7, 0xea])
--- a/test/testzcc.py Sun Nov 24 11:24:15 2013 +0100 +++ b/test/testzcc.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,10 +1,10 @@ import unittest -import glob import zcc import outstream import ppci import io import os +import target class ZccTestCase(unittest.TestCase): @@ -16,6 +16,8 @@ for fn in imps: arg_list.append('-i') arg_list.append(os.path.join(basedir, fn)) + arg_list.append('--target') + arg_list.append('arm') args = zcc.parser.parse_args(arg_list) self.assertEqual(0, zcc.main(args)) @@ -39,7 +41,8 @@ f = io.StringIO(src) diag = ppci.DiagnosticsManager() outs = outstream.TextOutputStream() - self.assertTrue(zcc.zcc([f], [], outs, diag)) + tg = target.armtarget + self.assertTrue(zcc.zcc([f], [], tg, outs, diag)) code = outs.getSection('code') self.assertEqual(0x08000000, code.address) data = outs.getSection('data')