# HG changeset patch # User Windel Bouwman # Date 1385288655 -3600 # Node ID 7b38782ed496665a22bc18b1dc5f1a1de54415de # Parent bd2593de3ff83615ba2488fedb77a84ee4d69bbc File moves diff -r bd2593de3ff8 -r 7b38782ed496 python/astviewer.py --- a/python/astviewer.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from c3 import Visitor, astnodes - -class AstModelBuilder: - def __init__(self): - self.functionIco = QIcon(QPixmap('icons/functionicon.png').scaled(32, 32)) - self.variableIco = QIcon(QPixmap('icons/variableicon.png').scaled(32, 32)) - self.model = QStandardItemModel() - self.model.setHorizontalHeaderLabels(['Object', 'Type']) - - def build(self, pkg): - #self.model.clear() - c = self.model.rowCount() - self.model.removeRows(0, c) - self.curItem = self.model.invisibleRootItem() - if pkg: - visitor = Visitor() - visitor.visit(pkg, self.p1, self.p2) - - def p1(self, node): - if type(node) is astnodes.Variable: - i = QStandardItem(self.variableIco, str(node)) - elif type(node) is astnodes.Function: - i = QStandardItem(self.functionIco, str(node)) - elif type(node) is astnodes.Package: - i = QStandardItem(str(node)) - else: - return - typ = str(node.typ) if hasattr(node, 'typ') else '' - ti = QStandardItem(str(typ)) - ti.setData(node) - i.setData(node) - self.curItem.appendRow([i, ti]) - self.curItem = i - - def p2(self, node): - if type(node) in [astnodes.Variable, astnodes.Function, astnodes.Package]: - self.curItem = self.curItem.parent() - -# The actual widget: -class AstViewer(QTreeView): - sigNodeSelected = pyqtSignal(object) - def __init__(self, parent=None): - super(AstViewer, self).__init__(parent) - self.clicked.connect(self.selectHandler) - self.modelBuilder = AstModelBuilder() - self.setModel(self.modelBuilder.model) - - def setAst(self, ast): - """ Create a new model and add all ast elements to it """ - self.modelBuilder.build(ast) - self.expandAll() - - def selectHandler(self, index): - if not index.isValid(): - return - model = self.model() - item = model.itemFromIndex(index) - node = item.data() - self.sigNodeSelected.emit(node) - - diff -r bd2593de3ff8 -r 7b38782ed496 python/bouncing_cube.py --- a/python/bouncing_cube.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,406 +0,0 @@ -from PyQt4.QtGui import * -from PyQt4.QtCore import * -from PyQt4.QtOpenGL import QGLWidget -from OpenGL.GL import * -from OpenGL.GLU import gluPerspective -import sys -from random import random -from math import pi, cos, sin, fabs, sqrt -from numpy import mat, array, ones, zeros, eye -from numpy.linalg import norm -import numpy as np -import time -import scipy.integrate -#import pyopencl - -""" - Test script that lets a dice bounce. - Converted from 20-sim equations into python code. - - 20-sim website: - http://www.20sim.com - -""" -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) - - 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,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(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 - -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() - - -def cross(A, B): - 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 - -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 - -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 - -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 - -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 - -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 - -def VTo4x4(V): - v1, v2, v3 = V.A1 - return mat(array( \ - [[0.0, -v3, v2, -v1], \ - [ v3, 0.0, -v1, -v2], \ - [-v2, v1, 0.0, -v3], \ - [v1, v2, v3, 0.0] ])) - -def homogeneous(R,p): - 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 - - -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) - - # The state vector! - state = mat(zeros( (13,1) )) - state[0:4, 0] = quatInitial - state[4:7, 0] = posInitial - state[7:13, 0] = PInitial - - return SCIPY(endtime, dt, state, parameters) - -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) - - 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 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): - 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): - 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) - drawAxis() - 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)) - - 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 -dt = 0.04 -print('starting integration... endtime =', et, ' stepsize =', dt) -t0 = time.time() -states = simulate(et, dt) -t1 = time.time() -print('That was heavy, it took me ', t1-t0, ' seconds!') -app = QApplication(sys.argv) -w = W(states, dt) -w.show() -sys.exit(app.exec_()) - diff -r bd2593de3ff8 -r 7b38782ed496 python/bouncing_cube_opencl.py --- a/python/bouncing_cube_opencl.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,406 +0,0 @@ -from PyQt4.QtGui import * -from PyQt4.QtCore import * -from PyQt4.QtOpenGL import QGLWidget -from OpenGL.GL import * -from OpenGL.GLU import gluPerspective -import sys -from random import random -from math import pi, cos, sin, fabs, sqrt -from numpy import mat, array, ones, zeros, eye -from numpy.linalg import norm -import numpy as np -import time -import scipy.integrate -import pyopencl - -""" - Test script that lets a dice bounce. - Converted from 20-sim equations into python code. - - 20-sim website: - http://www.20sim.com - -""" -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) - - 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,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(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 - -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() - - -def cross(A, B): - 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 - -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 - -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 - -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 - -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 - -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 - -def VTo4x4(V): - v1, v2, v3 = V.A1 - return mat(array( \ - [[0.0, -v3, v2, -v1], \ - [ v3, 0.0, -v1, -v2], \ - [-v2, v1, 0.0, -v3], \ - [v1, v2, v3, 0.0] ])) - -def homogeneous(R,p): - 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 - - -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) - - # The state vector! - state = mat(zeros( (13,1) )) - state[0:4, 0] = quatInitial - state[4:7, 0] = posInitial - state[7:13, 0] = PInitial - - return SCIPY(endtime, dt, state, parameters) - -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) - - 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 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): - 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): - 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) - drawAxis() - 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)) - - 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 -dt = 0.04 -print 'starting integration... endtime =', et, ' stepsize =', dt -t0 = time.time() -states = simulate(et, dt) -t1 = time.time() -print 'That was heavy, it took me ', t1-t0, ' seconds!' -app = QApplication(sys.argv) -w = W(states, dt) -w.show() -sys.exit(app.exec_()) - diff -r bd2593de3ff8 -r 7b38782ed496 python/codeedit.py --- a/python/codeedit.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -#!/usr/bin/python - -import sys -import os -from PyQt4.QtCore import * -from PyQt4.QtGui import * -import inspect - -GAP = 5 - -def clipVal(v, mn, mx): - if v < mn: return mn - if v > mx: return mx - return v - -class InnerCode(QWidget): - textChanged = pyqtSignal() - def __init__(self, scrollArea): - super().__init__(scrollArea) - self.scrollArea = scrollArea - self.setFont(QFont('Courier', 12)) - self.setFocusPolicy(Qt.StrongFocus) - # TODO: only beam cursor in text area.. - self.setCursor(Qt.IBeamCursor) - h = QFontMetrics(self.font()).height() - self.errorPixmap = QPixmap('icons/error.png').scaled(h, h) - self.arrowPixmap = QPixmap('icons/arrow.png').scaled(h, h) - self.blinkcursor = False - self.errorlist = [] - self.arrow = None - # Initial values: - self.setSource('') - self.CursorPosition = 0 - self.t = QTimer(self) - self.t.timeout.connect(self.updateCursor) - self.t.setInterval(500) - self.t.start() - - def updateCursor(self): - self.blinkcursor = not self.blinkcursor - self.update() - #self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) - - def setSource(self, src): - self.src = src - self.adjust() - - def getSource(self): - return self.src - - def setErrors(self, el): - self.errorlist = el - self.update() - - def setCursorPosition(self, c): - self.cursorPosition = clipVal(c, 0, len(self.src)) - self.update() - - CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition) - - @property - def Rows(self): - # Make this nicer: - return self.src.split('\n') - - @property - def CursorRow(self): - # TODO: make this nice. - txt = self.src[0:self.cursorPosition] - return len(txt.split('\n')) - - @property - def CursorCol(self): - txt = self.src[0:self.cursorPosition] - curLine = txt.split('\n')[-1] - return len(curLine) + 1 - - @property - def CurrentLine(self): - return self.getRow(self.CursorRow) - - def setRowCol(self, r, c): - prevRows = self.Rows[:r-1] - txt = '\n'.join(prevRows) - c = clipVal(c, 1, len(self.getRow(r))) - self.CursorPosition = len(txt) + c + 1 - self.showRow(self.CursorRow) - - def getRow(self, r): - rows = self.Rows - r = r - 1 - if r < 0 or r > len(rows) - 1: - return '' - else: - return rows[r] - - def showRow(self, r): - self.scrollArea.ensureVisible(self.xposTXT, r * self.charHeight, 4, self.charHeight) - - # Annotations: - def addAnnotation(self, row, col, ln, msg): - pass - - # Text modification: - def getChar(self, pos): - pass - - def insertText(self, txt): - self.setSource(self.src[0:self.CursorPosition] + txt + self.src[self.CursorPosition:]) - self.CursorPosition += len(txt) - self.textChanged.emit() - - def deleteChar(self): - self.setSource(self.src[0:self.CursorPosition] + self.src[self.CursorPosition+1:]) - self.textChanged.emit() - - def GotoNextChar(self): - if self.src[self.CursorPosition] != '\n': - self.CursorPosition += 1 - - def GotoPrevChar(self): - if self.src[self.CursorPosition - 1] != '\n': - self.CursorPosition -= 1 - - def GotoNextLine(self): - curLine = self.CurrentLine - c = self.CursorCol - 1 # go to zero based - self.CursorPosition += len(curLine) - c + 1 # line break char! - curLine = self.CurrentLine - if len(curLine) < c: - self.CursorPosition += len(curLine) - else: - self.CursorPosition += c - self.showRow(self.CursorRow) - - def GotoPrevLine(self): - c = self.CursorCol - 1 # go to zero based - self.CursorPosition -= c + 1 # line break char! - curLine = self.CurrentLine - if len(curLine) > c: - self.CursorPosition -= len(curLine) - c - self.showRow(self.CursorRow) - - def paintEvent(self, event): - # Helper variables: - er = event.rect() - chw, chh = self.charWidth, self.charHeight - painter = QPainter(self) - # Background: - painter.fillRect(er, self.palette().color(QPalette.Base)) - painter.fillRect(QRect(self.xposLNA, er.top(), 4 * chw, er.bottom() + 1), Qt.gray) - errorPen = QPen(Qt.red, 3) - # first and last row: - row1 = max(int(er.top() / chh) - 1, 1) - row2 = max(int(er.bottom() / chh) + 1, 1) - # Draw contents: - ypos = row1 * chh - self.charDescent - curRow = self.CursorRow - ydt = -chh + self.charDescent - for row in range(row1, row2 + 1): - if curRow == row and self.hasFocus(): - painter.fillRect(self.xposTXT, ypos + ydt, er.width(), chh, Qt.yellow) - # cursor - if self.blinkcursor: - cursorX = self.CursorCol * self.charWidth + self.xposTXT - self.charWidth - cursorY = ypos + ydt - painter.fillRect(cursorX, cursorY, 2, chh, Qt.black) - painter.setPen(Qt.black) - painter.drawText(self.xposLNA, ypos, '{0}'.format(row)) - xpos = self.xposTXT - painter.drawText(xpos, ypos, self.getRow(row)) - if self.arrow and self.arrow.row == row: - painter.drawPixmap(self.xposERR, ypos + ydt, self.arrowPixmap) - curErrors = [e for e in self.errorlist if e.loc and e.loc.row == row] - for e in curErrors: - painter.drawPixmap(self.xposERR, ypos + ydt, self.errorPixmap) - painter.setPen(errorPen) - x = self.xposTXT + (e.loc.col - 1) * chw - 2 - wt = e.loc.length * chw + 4 - dy = self.charDescent - painter.drawLine(x, ypos + dy, x + wt, ypos + dy) - #painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7) - # print error balloon - #painter.drawText(x, ypos + chh, e.msg) - #if len(curErrors) > 0: - # ypos += chh - ypos += chh - - def keyPressEvent(self, event): - if event.matches(QKeySequence.MoveToNextChar): - self.GotoNextChar() - elif event.matches(QKeySequence.MoveToPreviousChar): - self.GotoPrevChar() - elif event.matches(QKeySequence.MoveToNextLine): - self.GotoNextLine() - elif event.matches(QKeySequence.MoveToPreviousLine): - self.GotoPrevLine() - elif event.matches(QKeySequence.MoveToNextPage): - for i in range(5): - self.GotoNextLine() - elif event.matches(QKeySequence.MoveToPreviousPage): - for i in range(5): - self.GotoPrevLine() - elif event.matches(QKeySequence.MoveToEndOfLine): - self.CursorPosition += len(self.CurrentLine) - self.CursorCol + 1 - elif event.matches(QKeySequence.MoveToStartOfLine): - self.CursorPosition -= self.CursorCol - 1 - elif event.matches(QKeySequence.Delete): - self.deleteChar() - elif event.matches(QKeySequence.InsertParagraphSeparator): - self.insertText('\n') - elif event.key() == Qt.Key_Backspace: - self.CursorPosition -= 1 - self.deleteChar() - else: - char = event.text() - if char: - self.insertText(char) - self.update() - - def mousePressEvent(self, event): - pos = event.pos() - if pos.x() > self.xposTXT and pos.x(): - c = round((pos.x() - self.xposTXT) / self.charWidth) - r = int(pos.y() / self.charHeight) + 1 - self.setRowCol(r, c) - super().mousePressEvent(event) - - def adjust(self): - metrics = self.fontMetrics() - self.charHeight = metrics.height() - self.charWidth = metrics.width('x') - self.charDescent = metrics.descent() - self.xposERR = GAP - self.xposLNA = self.xposERR + GAP + self.errorPixmap.width() - self.xposTXT = self.xposLNA + 4 * self.charWidth + GAP - self.xposEnd = self.xposTXT + self.charWidth * 80 - self.setMinimumWidth(self.xposEnd) - txt = self.src.split('\n') - self.setMinimumHeight(self.charHeight * len(txt)) - self.update() - -class CodeEdit(QScrollArea): - def __init__(self): - super().__init__() - self.ic = InnerCode(self) - self.textChanged = self.ic.textChanged - self.setWidget(self.ic) - self.setWidgetResizable(True) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.setFocusPolicy(Qt.NoFocus) - self.showRow = self.ic.showRow - self.setRowCol = self.ic.setRowCol - self.FileName = None - Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v)) - - def setErrors(self, el): - self.ic.setErrors(el) - - def setFocus(self): - self.ic.setFocus() - super().setFocus() - - def setFileName(self, fn): - self.filename = fn - if fn: - fn = os.path.basename(fn) - else: - fn = 'Untitled' - self.setWindowTitle(fn) - - def getFileName(self): - return self.filename - FileName = property(getFileName, setFileName) - - def save(self): - if self.FileName: - s = self.Source - with open(self.FileName, 'w') as f: - f.write(s) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - ce = CodeEdit() - ce.show() - src = ''.join(inspect.getsourcelines(InnerCode)[0]) - ce.Source = src - ce.resize(600, 800) - app.exec() - diff -r bd2593de3ff8 -r 7b38782ed496 python/codegen.py --- a/python/codegen.py Thu Nov 21 15:46:50 2013 +0100 +++ b/python/codegen.py Sun Nov 24 11:24:15 2013 +0100 @@ -1,30 +1,65 @@ -import ir, target +import ir +import target from ppci import CompilerError +import transform +import canon + +# TODO: this class could be target independent: class CodeGenerator: - """ Target independent code generator """ - def __init__(self, tg): + def __init__(self, outs, target): + # TODO: schedule traces in better order. + # This is optional! assert isinstance(tg, target.Target) - self.tg = tg + self.target = target + self.ins_sel = ArmInstructionSelector() + self.ra = registerallocator.RegisterAllocator() + self.outs = outs + self.outs.getSection('code').address = 0x08000000 + self.outs.getSection('data').address = 0x20000000 + + def generateFunc(self, irfunc): + """ Generate code for one function into a frame """ + # Cleanup function: + transform.removeEmptyBlocks(irfunc) + + # Create a frame for this function: + frame = ArmFrame(irfunc.name) - def tryMap(self, ii): - for mi in self.tg.instructions: - if mi.irpattern is ii: - return mi.FromIr(ii) - raise CompilerError('Cannot map {0}'.format(ii)) + # Canonicalize the intermediate language: + canon.make(irfunc, frame) + self.ins_sel.munchFunction(irfunc, frame) + # Do register allocation: + 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) + return frame + def generate(self, ircode): assert isinstance(ircode, ir.Module) - obj = object() - for gvar in ircode.Variables: - print(gvar) - raise Exception() # TODO - for f in ircode.Functions: - for bb in f.Blocks: - for ins in bb.Instructions: - # Instruction selection: - #mi = self.tryMap(ins) - pass - return obj - + 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'))) + # 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? + return self.frames diff -r bd2593de3ff8 -r 7b38782ed496 python/codegenarm.py --- a/python/codegenarm.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ -import logging -import ir -from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo, Nop -from target import Imm3 -import cortexm3 as arm -from ppci import CompilerError -import registerallocator -from instructionselector import InstructionSelector -import irmach -from irmach import AbstractInstruction as makeIns -import canon -import transform -import asm - -class ArmFrame(irmach.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.rv = ir.Temp('special_RV') - self.p1 = ir.Temp('special_P1') - self.p2 = ir.Temp('special_P2') - self.p3 = ir.Temp('special_P3') - self.p4 = ir.Temp('special_P4') - 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.locVars = {} - self.parMap = {} - # Literal pool: - self.constants = [] - - def argLoc(self, pos): - """ - Gets the function parameter location in IR-code format. - """ - if pos == 0: - return self.p1 - elif pos == 1: - return self.p2 - elif pos == 2: - return self.p3 - elif pos == 3: - return self.p4 - else: - raise NotImplementedError('No more than 4 parameters implemented') - - def allocVar(self, lvar): - if lvar not in self.locVars: - self.locVars[lvar] = self.stacksize - self.stacksize = self.stacksize + 4 - return self.locVars[lvar] - - def addConstant(self, value): - lab_name = '{}_literal_{}'.format(self.name, len(self.constants)) - self.constants.append((lab_name, value)) - return lab_name - - def EntryExitGlue3(self): - """ - 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})))) - # Reserve stack space for locals: - self.instructions.insert(2, makeIns(arm.subspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize)))) - # Setup frame pointer: - self.instructions.insert(3, makeIns(arm.movregreg_ext_ins(arm.r7, arm.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})))) - # 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]) - - -# TODO: this class could be target independent: -class ArmCodeGenerator: - def __init__(self, outs): - # TODO: schedule traces in better order. - # This is optional! - self.ins_sel = ArmInstructionSelector() - self.ra = registerallocator.RegisterAllocator() - self.outs = outs - self.outs.getSection('code').address = 0x08000000 - self.outs.getSection('data').address = 0x20000000 - - def generateFunc(self, irfunc): - """ Generate code for one function into a frame """ - # Cleanup function: - transform.removeEmptyBlocks(irfunc) - - # Create a frame for this function: - frame = ArmFrame(irfunc.name) - - # Canonicalize the intermediate language: - canon.make(irfunc, frame) - self.ins_sel.munchFunction(irfunc, frame) - - # Do register allocation: - 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) - return frame - - def generate(self, ircode): - 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'))) - - # 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() - return self.frames - diff -r bd2593de3ff8 -r 7b38782ed496 python/cortexm3.py --- a/python/cortexm3.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,757 +0,0 @@ -import struct -import types -from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef -from target import Imm32, Imm7 -from asmnodes import ASymbol, ANumber, AUnop, ABinop -from ppci import CompilerError -import ir - -""" - ARM target description. -""" - -# TODO: encode this in DSL (domain specific language) -# TBD: is this required? - -def u16(h): - return struct.pack(' 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 - - -@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 - - -@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('> 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() - diff -r bd2593de3ff8 -r 7b38782ed496 python/diagrameditor.py --- a/python/diagrameditor.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,316 +0,0 @@ -#!/usr/bin/python - -from PyQt4.QtGui import * -from PyQt4.QtCore import * -import sys, json, base64 - -from diagramitems import Connection, ResizeSelectionHandle, Block, DiagramScene, CodeBlock -from icons import newicon, saveicon, loadicon -import diagramitems - -""" - Author: Windel Bouwman - Year: 2012 - Description: This script implements a diagram editor. - run with python 3.x as: - $ python [thisfile.py] -""" -def indent(lines): - return [' ' + line for line in lines] - -class ParameterDialog(QDialog): - def __init__(self, block, parent = None): - super(ParameterDialog, self).__init__(parent) - self.block = block - self.button = QPushButton('Ok', self) - self.nameEdit = QLineEdit(self.block.name) - self.codeEdit = QTextEdit(self) - self.codeEdit.setPlainText(self.block.code) - l = QFormLayout(self) - l.addRow('Name:', self.nameEdit) - l.addRow('Code:', self.codeEdit) - l.addWidget(self.button) - self.button.clicked.connect(self.OK) - def OK(self): - self.block.name = self.nameEdit.text() - self.block.code = self.codeEdit.toPlainText() - self.close() - -class EditorGraphicsView(QGraphicsView): - def __init__(self, parent=None): - QGraphicsView.__init__(self, parent) - self.setDragMode(QGraphicsView.RubberBandDrag) - self.delShort = QShortcut(QKeySequence.Delete, self) - self._model = None - self.treeView = QTreeView() - self.treeView.clicked.connect(self.itemActivated) - def itemActivated(self, idx): - b = idx.internalPointer() - s = b.scene() - s.clearSelection() - b.setSelected(True) - def setDiagram(self, d): - self.setScene(d) - self.delShort.activated.connect(d.deleteItems) - def getModel(self): - return self._model - def setModel(self, m): - self._model = m - if m: - self.treeView.setModel(m) - self.diagram = m.rootDiagram - self.model.modelReset.connect(self.treeView.expandAll) - model = property(getModel, setModel) - diagram = property(lambda s: s.scene(), setDiagram) - def save(self): - if self.model: - if not self.model.filename: - self.model.filename = QFileDialog.getSaveFileName(self) - if self.model.filename: - with open(self.model.filename, 'w') as f: - f.write(json.dumps(self.model.Dict, indent=2)) - def load(self): - filename = QFileDialog.getOpenFileName(self) - if filename: - self.model = loadModel(filename) - def newModel(self): - self.model = ModelHierarchyModel() - def goUp(self): - if hasattr(self.diagram, 'containingBlock'): - self.diagram = self.diagram.containingBlock.scene() - self.zoomAll() - def showCode(self): - if self.model: - c = self.model.gencode() - c = '\n'.join(c) - d = QDialog() - l = QFormLayout(d) - codeview = QTextEdit() - codeview.setPlainText(c) - l.addRow('code', codeview) - runButton = QPushButton('Run') - outputview = QTextEdit() - l.addRow('Output', outputview) - l.addWidget(runButton) - def print2(txt): - txt2 = outputview.toPlainText() - outputview.setPlainText(txt2 + '\n' + txt) - def runIt(): - outputview.clear() - globs = {'print': print2} - exec(codeview.toPlainText(), globs) - runButton.clicked.connect(runIt) - d.exec_() - def zoomAll(self): - """ zoom to fit all items """ - rect = self.diagram.itemsBoundingRect() - self.fitInView(rect, Qt.KeepAspectRatio) - def wheelEvent(self, event): - pos = event.pos() - posbefore = self.mapToScene(pos) - degrees = event.delta() / 8.0 - sx = (100.0 + degrees) / 100.0 - self.scale(sx, sx) - event.accept() - def dragEnterEvent(self, event): - if event.mimeData().hasFormat('component/name'): - event.accept() - def dragMoveEvent(self, event): - if event.mimeData().hasFormat('component/name'): event.accept() - def dropEvent(self, event): - if event.mimeData().hasFormat('component/name'): - name = bytes(event.mimeData().data('component/name')).decode() - kind, name = name.split(':') - pos = self.mapToScene(event.pos()) - s = self.scene() - if not s: - return - print(kind, 'name:', name) - kind = getattr(diagramitems, kind) - print(kind) - b = kind(s.uniqify(name)) - b.setPos(pos) - s.addItem(b) - -class LibraryModel(QStandardItemModel): - mimeTypes = lambda self: ['component/name'] - def mimeData(self, idxs): - mimedata = QMimeData() - for idx in idxs: - if idx.isValid(): - txt = self.data(idx, Qt.DisplayRole) - mimedata.setData('component/name', txt) - return mimedata - -class ModelHierarchyModel(QAbstractItemModel): - def __init__(self): - super(ModelHierarchyModel, self).__init__() - self.rootDiagram = DiagramScene() - self.rootDiagram.structureChanged.connect(self.handlechange) - self.filename = None - def handlechange(self): - self.modelReset.emit() - def setDict(self, d): - self.rootDiagram.Dict = d - self.modelReset.emit() - def getDict(self): - return self.rootDiagram.Dict - Dict = property(getDict, setDict) - def gencode(self): - c = ['def topLevel():'] - c += indent(self.rootDiagram.gencode()) - c.append('print("Running model")') - c.append('topLevel()') - c.append('print("Done")') - return c - def index(self, row, column, parent=None): - if parent.isValid(): - parent = parent.internalPointer().subModel - else: - parent = self.rootDiagram - blocks = sorted(parent.blocks, key=lambda b: b.name) - block = blocks[row] - # Store the index to retrieve it later in the parent function. - # TODO: solve this in a better way. - block.index = self.createIndex(row, column, block) - return block.index - def parent(self, index): - if index.isValid(): - block = index.internalPointer() - if block.scene() == self.rootDiagram: - return QModelIndex() - else: - print(block) - outerBlock = block.scene().containingBlock - return outerBlock.index - print('parent: No valid index') - def data(self, index, role): - if index.isValid() and role == Qt.DisplayRole: - b = index.internalPointer() - if index.column() == 0: - return b.name - elif index.column() == 1: - return str(type(b)) - def headerData(self, section, orientation, role): - if orientation == Qt.Horizontal and role == Qt.DisplayRole: - if section == 0: - return "Element" - elif section == 1: - return "Type" - else: - return "x" - def rowCount(self, parent): - if parent.column() > 0: - return 0 - if parent.isValid(): - block = parent.internalPointer() - if hasattr(block, 'subModel'): - return len(block.subModel.blocks) - else: - return 0 - else: - return len(self.rootDiagram.blocks) - def columnCount(self, parent): - return 2 - -class LibraryWidget(QListView): - def __init__(self): - super(LibraryWidget, self).__init__(None) - self.libraryModel = LibraryModel(self) - self.libraryModel.setColumnCount(1) - # Create an icon with an icon: - pixmap = QPixmap(60, 60) - pixmap.fill() - painter = QPainter(pixmap) - painter.fillRect(10, 10, 40, 40, Qt.blue) - painter.setBrush(Qt.yellow) - painter.drawEllipse(20, 20, 20, 20) - painter.end() - # Fill library: - for name in ['CodeBlock:codeBlock', 'DiagramBlock:submod', 'Block:blk']: - self.libraryModel.appendRow(QStandardItem(QIcon(pixmap), name)) - self.setModel(self.libraryModel) - self.setViewMode(self.IconMode) - self.setDragDropMode(self.DragOnly) - -def warning(txt): - QMessageBox.warning(None, "Warning", txt) - -def loadModel(filename): - try: - m = ModelHierarchyModel() - with open(filename, 'r') as f: data = f.read() - m.filename = filename - m.Dict = json.loads(data) - return m - except KeyError: - warning('Corrupt model: {0}'.format(filename)) - except ValueError: - warning('Corrupt model: {0}'.format(filename)) - except FileNotFoundError: - warning('File [{0}] not found'.format(filename)) - -class Main(QMainWindow): - def __init__(self): - super(Main, self).__init__(None) - self.editor = EditorGraphicsView() - self.setCentralWidget(self.editor) - self.setWindowTitle("Diagram editor") - def buildIcon(b64): - icon = base64.decodestring(b64) - pm = QPixmap() - pm.loadFromData(icon) - return QIcon(pm) - toolbar = self.addToolBar('Tools') - toolbar.setObjectName('Tools') - def act(name, shortcut, callback, icon=None): - a = QAction(icon, name, self) if icon else QAction(name, self) - a.setShortcuts(shortcut) - a.triggered.connect(callback) - toolbar.addAction(a) - act('New', QKeySequence.New, self.editor.newModel, buildIcon(newicon)) - act('Save', QKeySequence.Save, self.editor.save, buildIcon(saveicon)) - act('Load', QKeySequence.Open, self.editor.load, buildIcon(loadicon)) - act('Full screen', QKeySequence("F11"), self.toggleFullScreen) - act('Fit in view', QKeySequence("F8"), self.editor.zoomAll) - act('Go up', QKeySequence(Qt.Key_Up), self.editor.goUp) - act('Model code', QKeySequence("F7"), self.editor.showCode) - def addDock(name, widget): - dock = QDockWidget(name, self) - dock.setObjectName(name) - dock.setWidget(widget) - self.addDockWidget(Qt.LeftDockWidgetArea, dock) - addDock('Library', LibraryWidget()) - addDock('Model tree', self.editor.treeView) - self.settings = QSettings('windelsoft', 'diagrameditor') - self.loadSettings() - def toggleFullScreen(self): - self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) - self.editor.zoomAll() - def loadSettings(self): - if self.settings.contains('mainwindowstate'): - self.restoreState(self.settings.value('mainwindowstate')) - if self.settings.contains('mainwindowgeometry'): - self.restoreGeometry(self.settings.value('mainwindowgeometry')) - if self.settings.contains('openedmodel'): - modelfile = self.settings.value('openedmodel') - self.editor.model = loadModel(modelfile) - def closeEvent(self, ev): - self.settings.setValue('mainwindowstate', self.saveState()) - self.settings.setValue('mainwindowgeometry', self.saveGeometry()) - if self.editor.model and self.editor.model.filename: - self.settings.setValue('openedmodel', self.editor.model.filename) - # TODO: ask for save of opened files - else: - self.settings.remove('openedmodel') - ev.accept() - -if __name__ == '__main__': - if sys.version_info.major != 3: - print('Please use python 3.x') - sys.exit(1) - app = QApplication(sys.argv) - main = Main() - main.show() - app.exec_() - diff -r bd2593de3ff8 -r 7b38782ed496 python/hexedit.py --- a/python/hexedit.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,207 +0,0 @@ -#!/usr/bin/python - -import sys -import os -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from PyQt4 import uic - -BYTES_PER_LINE, GAP = 8, 12 - -def clamp(minimum, x, maximum): - return max(minimum, min(x, maximum)) - -def asciiChar(v): - if v < 0x20 or v > 0x7e: - return '.' - else: - return chr(v) - -class BinViewer(QWidget): - """ The view has an address, hex byte and ascii column """ - def __init__(self, scrollArea): - super().__init__(scrollArea) - self.scrollArea = scrollArea - self.setFont(QFont('Courier', 16)) - self.setFocusPolicy(Qt.StrongFocus) - self.blinkcursor = False - self.cursorX = self.cursorY = 0 - self.scrollArea = scrollArea - self.Data = bytearray() - self.Offset = 0 - t = QTimer(self) - t.timeout.connect(self.updateCursor) - t.setInterval(500) - t.start() - def updateCursor(self): - self.blinkcursor = not self.blinkcursor - self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) - def setCursorPosition(self, position): - position = clamp(0, int(position), len(self.Data) * 2 - 1) - self.cursorPosition = position - x = position % (2 * BYTES_PER_LINE) - x = x + int(x / 2) # Create a gap between hex values - self.cursorX = self.xposHex + x * self.charWidth - y = int(position / (2 * BYTES_PER_LINE)) - self.cursorY = y * self.charHeight + 2 - self.blinkcursor = True - self.update() - def getCursorPosition(self): - return self.cursorPosition - CursorPosition = property(getCursorPosition, setCursorPosition) - def setOffset(self, off): - self.offset = off - self.update() - Offset = property(lambda self: self.offset, setOffset) - def paintEvent(self, event): - # Helper variables: - er = event.rect() - chw, chh = self.charWidth, self.charHeight - painter = QPainter(self) - # Background: - painter.fillRect(er, self.palette().color(QPalette.Base)) - painter.fillRect(QRect(self.xposAddr, er.top(), 8 * chw, er.bottom() + 1), Qt.gray) - painter.setPen(Qt.gray) - x = self.xposAscii - (GAP / 2) - painter.drawLine(x, er.top(), x, er.bottom()) - x = self.xposEnd - (GAP / 2) - painter.drawLine(x, er.top(), x, er.bottom()) - # first and last index - firstIndex = max((int(er.top() / chh) - chh) * BYTES_PER_LINE, 0) - lastIndex = max((int(er.bottom() / chh) + chh) * BYTES_PER_LINE, 0) - yposStart = int(firstIndex / BYTES_PER_LINE) * chh + chh - # Draw contents: - painter.setPen(Qt.black) - ypos = yposStart - for index in range(firstIndex, lastIndex, BYTES_PER_LINE): - painter.setPen(Qt.black) - painter.drawText(self.xposAddr, ypos, '{0:08X}'.format(index + self.Offset)) - xpos = self.xposHex - xposAscii = self.xposAscii - for colIndex in range(BYTES_PER_LINE): - if index + colIndex < len(self.Data): - b = self.Data[index + colIndex] - bo = self.originalData[index + colIndex] - if b == bo: - painter.setPen(Qt.black) - else: - painter.setPen(Qt.red) - painter.drawText(xpos, ypos, '{0:02X}'.format(b)) - painter.drawText(xposAscii, ypos, asciiChar(b)) - xpos += 3 * chw - xposAscii += chw - ypos += chh - # cursor - if self.blinkcursor: - painter.fillRect(self.cursorX, self.cursorY + chh - 2, chw, 2, Qt.black) - def keyPressEvent(self, event): - if event.matches(QKeySequence.MoveToNextChar): - self.CursorPosition += 1 - if event.matches(QKeySequence.MoveToPreviousChar): - self.CursorPosition -= 1 - if event.matches(QKeySequence.MoveToNextLine): - self.CursorPosition += 2 * BYTES_PER_LINE - if event.matches(QKeySequence.MoveToPreviousLine): - self.CursorPosition -= 2 * BYTES_PER_LINE - if event.matches(QKeySequence.MoveToNextPage): - rows = int(self.scrollArea.viewport().height() / self.charHeight) - self.CursorPosition += (rows - 1) * 2 * BYTES_PER_LINE - if event.matches(QKeySequence.MoveToPreviousPage): - rows = int(self.scrollArea.viewport().height() / self.charHeight) - self.CursorPosition -= (rows - 1) * 2 * BYTES_PER_LINE - char = event.text().lower() - if char and char in '0123456789abcdef': - i = int(self.CursorPosition / 2) - hb = self.CursorPosition % 2 - v = int(char, 16) - if hb == 0: - # high half byte - self.data[i] = (self.data[i] & 0xF) | (v << 4) - else: - self.data[i] = (self.data[i] & 0xF0) | v - self.CursorPosition += 1 - self.scrollArea.ensureVisible(self.cursorX, self.cursorY + self.charHeight / 2, 4, self.charHeight / 2 + 4) - self.update() - def setCursorPositionAt(self, pos): - """ Calculate cursor position at a certain point """ - if pos.x() > self.xposHex and pos.x() < self.xposAscii: - x = round((2 * (pos.x() - self.xposHex)) / (self.charWidth * 3)) - y = int(pos.y() / self.charHeight) * 2 * BYTES_PER_LINE - self.setCursorPosition(x + y) - def mousePressEvent(self, event): - self.setCursorPositionAt(event.pos()) - def adjust(self): - self.charHeight = self.fontMetrics().height() - self.charWidth = self.fontMetrics().width('x') - self.xposAddr = GAP - self.xposHex = self.xposAddr + 8 * self.charWidth + GAP - self.xposAscii = self.xposHex + (BYTES_PER_LINE * 3 - 1) * self.charWidth + GAP - self.xposEnd = self.xposAscii + self.charWidth * BYTES_PER_LINE + GAP - self.setMinimumWidth(self.xposEnd) - if self.isVisible(): - sbw = self.scrollArea.verticalScrollBar().width() - self.scrollArea.setMinimumWidth(self.xposEnd + sbw + 5) - r = len(self.Data) % BYTES_PER_LINE - r = 1 if r > 0 else 0 - self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + r) * self.charHeight + 4) - self.scrollArea.setMinimumHeight(self.charHeight * 8) - self.update() - def showEvent(self, e): - self.adjust() - super().showEvent(e) - def setData(self, d): - self.data = bytearray(d) - self.originalData = bytearray(d) - self.adjust() - self.setCursorPosition(0) - Data = property(lambda self: self.data, setData) - -class HexEdit(QScrollArea): - def __init__(self): - super().__init__() - self.bv = BinViewer(self) - self.setWidget(self.bv) - self.setWidgetResizable(True) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.setFocusPolicy(Qt.NoFocus) - -class HexEditor(QMainWindow): - def __init__(self): - super().__init__() - basedir = os.path.dirname(__file__) - uic.loadUi(os.path.join(basedir, 'hexeditor.ui'), baseinstance=self) - self.he = HexEdit() - self.setCentralWidget(self.he) - self.actionOpen.triggered.connect(self.doOpen) - self.actionSave.triggered.connect(self.doSave) - self.actionSaveAs.triggered.connect(self.doSaveAs) - self.fileName = None - self.updateControls() - def updateControls(self): - s = True if self.fileName else False - self.actionSave.setEnabled(s) - self.actionSaveAs.setEnabled(s) - def doOpen(self): - filename = QFileDialog.getOpenFileName(self) - if filename: - with open(filename, 'rb') as f: - self.he.bv.Data = f.read() - self.fileName = filename - self.updateControls() - def doSave(self): - self.updateControls() - def doSaveAs(self): - filename = QFileDialog.getSaveFileName(self) - if filename: - with open(filename, 'wb') as f: - f.write(self.he.bv.Data) - self.fileName = filename - self.updateControls() - -if __name__ == '__main__': - app = QApplication(sys.argv) - he = HexEditor() - he.show() - #he.bv.Data = bytearray(range(100)) * 8 + b'x' - app.exec() - diff -r bd2593de3ff8 -r 7b38782ed496 python/hexeditor.ui --- a/python/hexeditor.ui Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 617 - 503 - - - - HexEditor - - - - - - 0 - 0 - 617 - 25 - - - - - File - - - - - - - - - - - toolBar - - - TopToolBarArea - - - false - - - - - - - - Open - - - Opens a file for editing - - - Ctrl+O - - - - - Save - - - Ctrl+S - - - - - Save As - - - - - - diff -r bd2593de3ff8 -r 7b38782ed496 python/hexutil.py --- a/python/hexutil.py Thu Nov 21 15:46:50 2013 +0100 +++ b/python/hexutil.py Sun Nov 24 11:24:15 2013 +0100 @@ -28,6 +28,7 @@ p.add_argument('hexfile2', type=argparse.FileType('r'), help="hexfile 2") p.add_argument('rhexfile', type=argparse.FileType('w'), help="resulting hexfile") + def main(args): if args.command == 'info': hf = HexFile() @@ -56,4 +57,3 @@ parser.print_usage() sys.exit(1) main(args) - diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/arrow.png Binary file python/icons/arrow.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/chip.png Binary file python/icons/chip.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/error.png Binary file python/icons/error.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/functionicon.png Binary file python/icons/functionicon.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/hardware.png Binary file python/icons/hardware.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/info.png Binary file python/icons/info.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/logo.png Binary file python/icons/logo.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/variableicon.png Binary file python/icons/variableicon.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/icons/warning.png Binary file python/icons/warning.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide.py --- a/python/ide.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -#!/usr/bin/python - -import sys -import os -import logging -import traceback -import io - -from PyQt4.QtCore import * -from PyQt4.QtGui import * - -# Compiler imports: -import ppci -from astviewer import AstViewer -from codeedit import CodeEdit -from logview import LogView as BuildOutput -from disasm import Disassembly -stutil = __import__('st-util') -import c3 -import zcc -import outstream - - -def handle_exception(tp, v, tb): - logging.critical(str(v)) - tb = traceback.format_tb(tb) - for i in tb: - logging.critical(i.strip()) - -sys.excepthook = handle_exception - -class BuildErrors(QTreeView): - sigErrorSelected = pyqtSignal(object) - - def __init__(self, parent=None): - super(BuildErrors, self).__init__(parent) - model = QStandardItemModel() - self.setModel(model) - self.clicked.connect(self.itemSelected) - self.errorIcon = QIcon('icons/error.png') - self.model = QStandardItemModel() - self.model.setHorizontalHeaderLabels(['Message', 'Row', 'Column']) - self.header().setStretchLastSection(True) - self.setModel(self.model) - - def setErrorList(self, errorlist): - c = self.model.rowCount() - self.model.removeRows(0, c) - for e in errorlist: - item = QStandardItem(self.errorIcon, str(e.msg)) - item.setData(e) - row = str(e.loc.row) if e.loc else '' - irow = QStandardItem(row) - irow.setData(e) - col = str(e.loc.col) if e.loc else '' - icol = QStandardItem(col) - icol.setData(e) - self.model.appendRow([item, irow, icol]) - for i in range(3): - self.resizeColumnToContents(i) - - def itemSelected(self, index): - if not index.isValid(): - return - item = self.model.itemFromIndex(index) - err = item.data() - self.sigErrorSelected.emit(err) - - - -class AboutDialog(QDialog): - def __init__(self, parent=None): - super(AboutDialog, self).__init__(parent) - self.setWindowTitle('About') - l = QVBoxLayout(self) - txt = QTextEdit(self) - txt.setReadOnly(True) - with open(os.path.join('..', 'readme.rst'), 'r') as f: - aboutText = f.read() - txt.append(aboutText) - l.addWidget(txt) - but = QPushButton('OK') - but.setDefault(True) - but.clicked.connect(self.close) - l.addWidget(but) - - -class Ide(QMainWindow): - def __init__(self, parent=None): - super(Ide, self).__init__(parent) - self.to_open_files = [] - self.logger = logging.getLogger('ide') - - self.setWindowTitle('LCFOS IDE') - icon = QIcon('icons/logo.png') - self.setWindowIcon(icon) - - # Create menus: - mb = self.menuBar() - self.fileMenu = mb.addMenu('File') - self.viewMenu = mb.addMenu('View') - self.helpMenu = mb.addMenu('Help') - - # Create mdi area: - self.mdiArea = QMdiArea() - self.mdiArea.setViewMode(QMdiArea.TabbedView) - self.mdiArea.setTabsClosable(True) - self.mdiArea.setTabsMovable(True) - self.setCentralWidget(self.mdiArea) - - # Create components: - def addComponent(name, widget): - dw = QDockWidget(name) - dw.setWidget(widget) - dw.setObjectName(name) - self.addDockWidget(Qt.RightDockWidgetArea, dw) - self.viewMenu.addAction(dw.toggleViewAction()) - return widget - - self.buildOutput = addComponent('Build output', BuildOutput()) - self.astViewer = addComponent('AST viewer', AstViewer()) - self.astViewer.sigNodeSelected.connect(lambda node: self.showLoc(node.loc)) - self.builderrors = addComponent('Build errors', BuildErrors()) - self.builderrors.sigErrorSelected.connect(lambda err: self.showLoc(err.loc)) - self.devxplr = addComponent('Device explorer', stutil.DeviceExplorer()) - self.regview = addComponent('Registers', stutil.RegisterView()) - self.memview = addComponent('Memory', stutil.MemoryView()) - self.disasm = addComponent('Disasm', Disassembly()) - self.ctrlToolbar = stutil.DebugToolbar() - self.addToolBar(self.ctrlToolbar) - self.ctrlToolbar.setObjectName('debugToolbar') - self.devxplr.deviceSelected.connect(self.regview.mdl.setDevice) - self.ctrlToolbar.statusChange.connect(self.memview.refresh) - self.devxplr.deviceSelected.connect(self.memview.setDevice) - self.devxplr.deviceSelected.connect(self.ctrlToolbar.setDevice) - self.ctrlToolbar.statusChange.connect(self.regview.refresh) - self.ctrlToolbar.codePosition.connect(self.pointCode) - - # About dialog: - self.aboutDialog = AboutDialog() - self.aboutDialog.setWindowIcon(icon) - - # Create actions: - def addMenuEntry(name, menu, callback, shortcut=None): - a = QAction(name, self) - menu.addAction(a) - a.triggered.connect(callback) - if shortcut: - a.setShortcut(shortcut) - - addMenuEntry("New", self.fileMenu, self.newFile, shortcut=QKeySequence(QKeySequence.New)) - addMenuEntry("Open", self.fileMenu, self.openFile, shortcut=QKeySequence(QKeySequence.Open)) - addMenuEntry("Save", self.fileMenu, self.saveFile, shortcut=QKeySequence(QKeySequence.Save)) - addMenuEntry("Build", self.fileMenu, self.buildFile, shortcut=QKeySequence("F7")) - addMenuEntry("Build and flash", self.fileMenu, self.buildFileAndFlash, shortcut=QKeySequence("F8")) - - self.helpAction = QAction('Help', self) - self.helpAction.setShortcut(QKeySequence('F1')) - self.helpMenu.addAction(self.helpAction) - addMenuEntry('About', self.helpMenu, self.aboutDialog.open) - - addMenuEntry('Cascade windows', self.viewMenu, self.mdiArea.cascadeSubWindows) - addMenuEntry('Tile windows', self.viewMenu, self.mdiArea.tileSubWindows) - sb = self.statusBar() - - # Load settings: - self.settings = QSettings('windelsoft', 'lcfoside') - self.loadSettings() - self.diag = ppci.DiagnosticsManager() - self.c3front = c3.Builder(self.diag) - - # File handling: - def newFile(self): - self.newCodeEdit() - - def openFile(self): - filename = QFileDialog.getOpenFileName(self, "Open C3 file...", "*.c3", - "C3 source files (*.c3)") - if filename: - self.loadFile(filename) - - def saveFile(self): - ac = self.activeMdiChild() - if ac: - ac.save() - - def loadFile(self, filename): - ce = self.newCodeEdit() - try: - with open(filename) as f: - ce.Source = f.read() - ce.FileName = filename - except Exception as e: - print('exception opening file', e) - - # MDI: - def newCodeEdit(self): - ce = CodeEdit() - ce.textChanged.connect(self.parseFile) - w = self.mdiArea.addSubWindow(ce) - self.mdiArea.setActiveSubWindow(w) - ce.showMaximized() - return ce - - def activeMdiChild(self): - aw = self.mdiArea.activeSubWindow() - if aw: - return aw.widget() - - def findMdiChild(self, filename): - for wid in self.allChildren(): - if wid.filename == filename: - return wid - - def allChildren(self): - return [w.widget() for w in self.mdiArea.subWindowList()] - - # Settings: - def loadSettings(self): - if self.settings.contains('mainwindowstate'): - self.restoreState(self.settings.value('mainwindowstate')) - if self.settings.contains('mainwindowgeometry'): - self.restoreGeometry(self.settings.value('mainwindowgeometry')) - if self.settings.contains('lastfiles'): - lfs = self.settings.value('lastfiles') - if lfs: - self.to_open_files.extend(lfs) - - def showEvent(self, ev): - super().showEvent(ev) - while self.to_open_files: - fn = self.to_open_files.pop(0) - self.loadFile(fn) - - def closeEvent(self, ev): - self.settings.setValue('mainwindowstate', self.saveState()) - self.settings.setValue('mainwindowgeometry', self.saveGeometry()) - ac = self.activeMdiChild() - lfs = [ce.FileName for ce in self.allChildren() if ce.FileName] - self.settings.setValue('lastfiles', lfs) - ev.accept() - - # Error handling: - def nodeSelected(self, node): - self.showLoc(node.loc) - - def showLoc(self, loc): - ce = self.activeMdiChild() - if not ce: - return - if loc: - ce.setRowCol(loc.row, loc.col) - ce.setFocus() - - def pointCode(self, p): - # Lookup pc in debug infos: - loc = None - print(p) - self.disasm.showPos(p) - if hasattr(self, 'debugInfo'): - for di in self.debugInfo: - if di.address > p: - loc = di.info - break - if loc: - ce = self.activeMdiChild() - if ce: - ce.ic.arrow = loc - self.showLoc(loc) - - # Build recepy: - def parseFile(self): - self.logger.info('Parsing!') - ce = self.activeMdiChild() - if not ce: - return - self.diag.clear() - pkg = self.c3front.parse(ce.Source) - - # Set errors: - self.builderrors.setErrorList(self.diag.diags) - ce.setErrors(self.diag.diags) - self.astViewer.setAst(pkg) - if pkg: - c3.AstPrinter().printAst(pkg) - self.logger.info('Done!') - - def buildFile(self): - ce = self.activeMdiChild() - if not ce: - return - fn = ce.FileName - self.diag.clear() - outs = outstream.TextOutputStream() - if not zcc.zcc([io.StringIO(ce.Source)], [], outs, self.diag): - # Set errors: - self.builderrors.setErrorList(self.diag.diags) - ce.setErrors(self.diag.diags) - return - - def buildFileAndFlash(self): - ce = self.activeMdiChild() - if not ce: - return - fn = ce.FileName - self.diag.clear() - outs = outstream.TextOutputStream() - imps = [open(ce.FileName, 'r') for ce in self.allChildren() if ce.FileName and ce.FileName != fn] - if not zcc.zcc([open(fn, 'r')], imps, outs, self.diag): - # Set errors: - self.builderrors.setErrorList(self.diag.diags) - ce.setErrors(self.diag.diags) - return - - outs.dump() - code_s = outs.getSection('code') - self.disasm.dm.setInstructions(code_s.instructions) - self.debugInfo = code_s.debugInfos() - if self.ctrlToolbar.device: - logging.info('Flashing stm32f4 discovery') - bts = code_s.to_bytes() - self.ctrlToolbar.device.writeFlash(0x08000000, bts) - stl = self.ctrlToolbar.device.iface - stl.reset() - stl.halt() - stl.run() - logging.info('Done!') - else: - self.logger.warning('Not connected to device, skipping flash') - - -if __name__ == '__main__': - logging.basicConfig(format=zcc.logformat, level=logging.DEBUG) - app = QApplication(sys.argv) - ide = Ide() - ide.show() - ide.logger.info('IDE started') - app.exec_() diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/astviewer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/astviewer.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,63 @@ +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from c3 import Visitor, astnodes + +class AstModelBuilder: + def __init__(self): + self.functionIco = QIcon(QPixmap('icons/functionicon.png').scaled(32, 32)) + self.variableIco = QIcon(QPixmap('icons/variableicon.png').scaled(32, 32)) + self.model = QStandardItemModel() + self.model.setHorizontalHeaderLabels(['Object', 'Type']) + + def build(self, pkg): + #self.model.clear() + c = self.model.rowCount() + self.model.removeRows(0, c) + self.curItem = self.model.invisibleRootItem() + if pkg: + visitor = Visitor() + visitor.visit(pkg, self.p1, self.p2) + + def p1(self, node): + if type(node) is astnodes.Variable: + i = QStandardItem(self.variableIco, str(node)) + elif type(node) is astnodes.Function: + i = QStandardItem(self.functionIco, str(node)) + elif type(node) is astnodes.Package: + i = QStandardItem(str(node)) + else: + return + typ = str(node.typ) if hasattr(node, 'typ') else '' + ti = QStandardItem(str(typ)) + ti.setData(node) + i.setData(node) + self.curItem.appendRow([i, ti]) + self.curItem = i + + def p2(self, node): + if type(node) in [astnodes.Variable, astnodes.Function, astnodes.Package]: + self.curItem = self.curItem.parent() + +# The actual widget: +class AstViewer(QTreeView): + sigNodeSelected = pyqtSignal(object) + def __init__(self, parent=None): + super(AstViewer, self).__init__(parent) + self.clicked.connect(self.selectHandler) + self.modelBuilder = AstModelBuilder() + self.setModel(self.modelBuilder.model) + + def setAst(self, ast): + """ Create a new model and add all ast elements to it """ + self.modelBuilder.build(ast) + self.expandAll() + + def selectHandler(self, index): + if not index.isValid(): + return + model = self.model() + item = model.itemFromIndex(index) + node = item.data() + self.sigNodeSelected.emit(node) + + diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/codeedit.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/codeedit.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,291 @@ +#!/usr/bin/python + +import sys +import os +from PyQt4.QtCore import * +from PyQt4.QtGui import * +import inspect + +GAP = 5 + +def clipVal(v, mn, mx): + if v < mn: return mn + if v > mx: return mx + return v + +class InnerCode(QWidget): + textChanged = pyqtSignal() + def __init__(self, scrollArea): + super().__init__(scrollArea) + self.scrollArea = scrollArea + self.setFont(QFont('Courier', 12)) + self.setFocusPolicy(Qt.StrongFocus) + # TODO: only beam cursor in text area.. + self.setCursor(Qt.IBeamCursor) + h = QFontMetrics(self.font()).height() + self.errorPixmap = QPixmap('icons/error.png').scaled(h, h) + self.arrowPixmap = QPixmap('icons/arrow.png').scaled(h, h) + self.blinkcursor = False + self.errorlist = [] + self.arrow = None + # Initial values: + self.setSource('') + self.CursorPosition = 0 + self.t = QTimer(self) + self.t.timeout.connect(self.updateCursor) + self.t.setInterval(500) + self.t.start() + + def updateCursor(self): + self.blinkcursor = not self.blinkcursor + self.update() + #self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) + + def setSource(self, src): + self.src = src + self.adjust() + + def getSource(self): + return self.src + + def setErrors(self, el): + self.errorlist = el + self.update() + + def setCursorPosition(self, c): + self.cursorPosition = clipVal(c, 0, len(self.src)) + self.update() + + CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition) + + @property + def Rows(self): + # Make this nicer: + return self.src.split('\n') + + @property + def CursorRow(self): + # TODO: make this nice. + txt = self.src[0:self.cursorPosition] + return len(txt.split('\n')) + + @property + def CursorCol(self): + txt = self.src[0:self.cursorPosition] + curLine = txt.split('\n')[-1] + return len(curLine) + 1 + + @property + def CurrentLine(self): + return self.getRow(self.CursorRow) + + def setRowCol(self, r, c): + prevRows = self.Rows[:r-1] + txt = '\n'.join(prevRows) + c = clipVal(c, 1, len(self.getRow(r))) + self.CursorPosition = len(txt) + c + 1 + self.showRow(self.CursorRow) + + def getRow(self, r): + rows = self.Rows + r = r - 1 + if r < 0 or r > len(rows) - 1: + return '' + else: + return rows[r] + + def showRow(self, r): + self.scrollArea.ensureVisible(self.xposTXT, r * self.charHeight, 4, self.charHeight) + + # Annotations: + def addAnnotation(self, row, col, ln, msg): + pass + + # Text modification: + def getChar(self, pos): + pass + + def insertText(self, txt): + self.setSource(self.src[0:self.CursorPosition] + txt + self.src[self.CursorPosition:]) + self.CursorPosition += len(txt) + self.textChanged.emit() + + def deleteChar(self): + self.setSource(self.src[0:self.CursorPosition] + self.src[self.CursorPosition+1:]) + self.textChanged.emit() + + def GotoNextChar(self): + if self.src[self.CursorPosition] != '\n': + self.CursorPosition += 1 + + def GotoPrevChar(self): + if self.src[self.CursorPosition - 1] != '\n': + self.CursorPosition -= 1 + + def GotoNextLine(self): + curLine = self.CurrentLine + c = self.CursorCol - 1 # go to zero based + self.CursorPosition += len(curLine) - c + 1 # line break char! + curLine = self.CurrentLine + if len(curLine) < c: + self.CursorPosition += len(curLine) + else: + self.CursorPosition += c + self.showRow(self.CursorRow) + + def GotoPrevLine(self): + c = self.CursorCol - 1 # go to zero based + self.CursorPosition -= c + 1 # line break char! + curLine = self.CurrentLine + if len(curLine) > c: + self.CursorPosition -= len(curLine) - c + self.showRow(self.CursorRow) + + def paintEvent(self, event): + # Helper variables: + er = event.rect() + chw, chh = self.charWidth, self.charHeight + painter = QPainter(self) + # Background: + painter.fillRect(er, self.palette().color(QPalette.Base)) + painter.fillRect(QRect(self.xposLNA, er.top(), 4 * chw, er.bottom() + 1), Qt.gray) + errorPen = QPen(Qt.red, 3) + # first and last row: + row1 = max(int(er.top() / chh) - 1, 1) + row2 = max(int(er.bottom() / chh) + 1, 1) + # Draw contents: + ypos = row1 * chh - self.charDescent + curRow = self.CursorRow + ydt = -chh + self.charDescent + for row in range(row1, row2 + 1): + if curRow == row and self.hasFocus(): + painter.fillRect(self.xposTXT, ypos + ydt, er.width(), chh, Qt.yellow) + # cursor + if self.blinkcursor: + cursorX = self.CursorCol * self.charWidth + self.xposTXT - self.charWidth + cursorY = ypos + ydt + painter.fillRect(cursorX, cursorY, 2, chh, Qt.black) + painter.setPen(Qt.black) + painter.drawText(self.xposLNA, ypos, '{0}'.format(row)) + xpos = self.xposTXT + painter.drawText(xpos, ypos, self.getRow(row)) + if self.arrow and self.arrow.row == row: + painter.drawPixmap(self.xposERR, ypos + ydt, self.arrowPixmap) + curErrors = [e for e in self.errorlist if e.loc and e.loc.row == row] + for e in curErrors: + painter.drawPixmap(self.xposERR, ypos + ydt, self.errorPixmap) + painter.setPen(errorPen) + x = self.xposTXT + (e.loc.col - 1) * chw - 2 + wt = e.loc.length * chw + 4 + dy = self.charDescent + painter.drawLine(x, ypos + dy, x + wt, ypos + dy) + #painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7) + # print error balloon + #painter.drawText(x, ypos + chh, e.msg) + #if len(curErrors) > 0: + # ypos += chh + ypos += chh + + def keyPressEvent(self, event): + if event.matches(QKeySequence.MoveToNextChar): + self.GotoNextChar() + elif event.matches(QKeySequence.MoveToPreviousChar): + self.GotoPrevChar() + elif event.matches(QKeySequence.MoveToNextLine): + self.GotoNextLine() + elif event.matches(QKeySequence.MoveToPreviousLine): + self.GotoPrevLine() + elif event.matches(QKeySequence.MoveToNextPage): + for i in range(5): + self.GotoNextLine() + elif event.matches(QKeySequence.MoveToPreviousPage): + for i in range(5): + self.GotoPrevLine() + elif event.matches(QKeySequence.MoveToEndOfLine): + self.CursorPosition += len(self.CurrentLine) - self.CursorCol + 1 + elif event.matches(QKeySequence.MoveToStartOfLine): + self.CursorPosition -= self.CursorCol - 1 + elif event.matches(QKeySequence.Delete): + self.deleteChar() + elif event.matches(QKeySequence.InsertParagraphSeparator): + self.insertText('\n') + elif event.key() == Qt.Key_Backspace: + self.CursorPosition -= 1 + self.deleteChar() + else: + char = event.text() + if char: + self.insertText(char) + self.update() + + def mousePressEvent(self, event): + pos = event.pos() + if pos.x() > self.xposTXT and pos.x(): + c = round((pos.x() - self.xposTXT) / self.charWidth) + r = int(pos.y() / self.charHeight) + 1 + self.setRowCol(r, c) + super().mousePressEvent(event) + + def adjust(self): + metrics = self.fontMetrics() + self.charHeight = metrics.height() + self.charWidth = metrics.width('x') + self.charDescent = metrics.descent() + self.xposERR = GAP + self.xposLNA = self.xposERR + GAP + self.errorPixmap.width() + self.xposTXT = self.xposLNA + 4 * self.charWidth + GAP + self.xposEnd = self.xposTXT + self.charWidth * 80 + self.setMinimumWidth(self.xposEnd) + txt = self.src.split('\n') + self.setMinimumHeight(self.charHeight * len(txt)) + self.update() + +class CodeEdit(QScrollArea): + def __init__(self): + super().__init__() + self.ic = InnerCode(self) + self.textChanged = self.ic.textChanged + self.setWidget(self.ic) + self.setWidgetResizable(True) + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + self.setFocusPolicy(Qt.NoFocus) + self.showRow = self.ic.showRow + self.setRowCol = self.ic.setRowCol + self.FileName = None + Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v)) + + def setErrors(self, el): + self.ic.setErrors(el) + + def setFocus(self): + self.ic.setFocus() + super().setFocus() + + def setFileName(self, fn): + self.filename = fn + if fn: + fn = os.path.basename(fn) + else: + fn = 'Untitled' + self.setWindowTitle(fn) + + def getFileName(self): + return self.filename + FileName = property(getFileName, setFileName) + + def save(self): + if self.FileName: + s = self.Source + with open(self.FileName, 'w') as f: + f.write(s) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + ce = CodeEdit() + ce.show() + src = ''.join(inspect.getsourcelines(InnerCode)[0]) + ce.Source = src + ce.resize(600, 800) + app.exec() + diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/hexedit.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/hexedit.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,207 @@ +#!/usr/bin/python + +import sys +import os +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from PyQt4 import uic + +BYTES_PER_LINE, GAP = 8, 12 + +def clamp(minimum, x, maximum): + return max(minimum, min(x, maximum)) + +def asciiChar(v): + if v < 0x20 or v > 0x7e: + return '.' + else: + return chr(v) + +class BinViewer(QWidget): + """ The view has an address, hex byte and ascii column """ + def __init__(self, scrollArea): + super().__init__(scrollArea) + self.scrollArea = scrollArea + self.setFont(QFont('Courier', 16)) + self.setFocusPolicy(Qt.StrongFocus) + self.blinkcursor = False + self.cursorX = self.cursorY = 0 + self.scrollArea = scrollArea + self.Data = bytearray() + self.Offset = 0 + t = QTimer(self) + t.timeout.connect(self.updateCursor) + t.setInterval(500) + t.start() + def updateCursor(self): + self.blinkcursor = not self.blinkcursor + self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) + def setCursorPosition(self, position): + position = clamp(0, int(position), len(self.Data) * 2 - 1) + self.cursorPosition = position + x = position % (2 * BYTES_PER_LINE) + x = x + int(x / 2) # Create a gap between hex values + self.cursorX = self.xposHex + x * self.charWidth + y = int(position / (2 * BYTES_PER_LINE)) + self.cursorY = y * self.charHeight + 2 + self.blinkcursor = True + self.update() + def getCursorPosition(self): + return self.cursorPosition + CursorPosition = property(getCursorPosition, setCursorPosition) + def setOffset(self, off): + self.offset = off + self.update() + Offset = property(lambda self: self.offset, setOffset) + def paintEvent(self, event): + # Helper variables: + er = event.rect() + chw, chh = self.charWidth, self.charHeight + painter = QPainter(self) + # Background: + painter.fillRect(er, self.palette().color(QPalette.Base)) + painter.fillRect(QRect(self.xposAddr, er.top(), 8 * chw, er.bottom() + 1), Qt.gray) + painter.setPen(Qt.gray) + x = self.xposAscii - (GAP / 2) + painter.drawLine(x, er.top(), x, er.bottom()) + x = self.xposEnd - (GAP / 2) + painter.drawLine(x, er.top(), x, er.bottom()) + # first and last index + firstIndex = max((int(er.top() / chh) - chh) * BYTES_PER_LINE, 0) + lastIndex = max((int(er.bottom() / chh) + chh) * BYTES_PER_LINE, 0) + yposStart = int(firstIndex / BYTES_PER_LINE) * chh + chh + # Draw contents: + painter.setPen(Qt.black) + ypos = yposStart + for index in range(firstIndex, lastIndex, BYTES_PER_LINE): + painter.setPen(Qt.black) + painter.drawText(self.xposAddr, ypos, '{0:08X}'.format(index + self.Offset)) + xpos = self.xposHex + xposAscii = self.xposAscii + for colIndex in range(BYTES_PER_LINE): + if index + colIndex < len(self.Data): + b = self.Data[index + colIndex] + bo = self.originalData[index + colIndex] + if b == bo: + painter.setPen(Qt.black) + else: + painter.setPen(Qt.red) + painter.drawText(xpos, ypos, '{0:02X}'.format(b)) + painter.drawText(xposAscii, ypos, asciiChar(b)) + xpos += 3 * chw + xposAscii += chw + ypos += chh + # cursor + if self.blinkcursor: + painter.fillRect(self.cursorX, self.cursorY + chh - 2, chw, 2, Qt.black) + def keyPressEvent(self, event): + if event.matches(QKeySequence.MoveToNextChar): + self.CursorPosition += 1 + if event.matches(QKeySequence.MoveToPreviousChar): + self.CursorPosition -= 1 + if event.matches(QKeySequence.MoveToNextLine): + self.CursorPosition += 2 * BYTES_PER_LINE + if event.matches(QKeySequence.MoveToPreviousLine): + self.CursorPosition -= 2 * BYTES_PER_LINE + if event.matches(QKeySequence.MoveToNextPage): + rows = int(self.scrollArea.viewport().height() / self.charHeight) + self.CursorPosition += (rows - 1) * 2 * BYTES_PER_LINE + if event.matches(QKeySequence.MoveToPreviousPage): + rows = int(self.scrollArea.viewport().height() / self.charHeight) + self.CursorPosition -= (rows - 1) * 2 * BYTES_PER_LINE + char = event.text().lower() + if char and char in '0123456789abcdef': + i = int(self.CursorPosition / 2) + hb = self.CursorPosition % 2 + v = int(char, 16) + if hb == 0: + # high half byte + self.data[i] = (self.data[i] & 0xF) | (v << 4) + else: + self.data[i] = (self.data[i] & 0xF0) | v + self.CursorPosition += 1 + self.scrollArea.ensureVisible(self.cursorX, self.cursorY + self.charHeight / 2, 4, self.charHeight / 2 + 4) + self.update() + def setCursorPositionAt(self, pos): + """ Calculate cursor position at a certain point """ + if pos.x() > self.xposHex and pos.x() < self.xposAscii: + x = round((2 * (pos.x() - self.xposHex)) / (self.charWidth * 3)) + y = int(pos.y() / self.charHeight) * 2 * BYTES_PER_LINE + self.setCursorPosition(x + y) + def mousePressEvent(self, event): + self.setCursorPositionAt(event.pos()) + def adjust(self): + self.charHeight = self.fontMetrics().height() + self.charWidth = self.fontMetrics().width('x') + self.xposAddr = GAP + self.xposHex = self.xposAddr + 8 * self.charWidth + GAP + self.xposAscii = self.xposHex + (BYTES_PER_LINE * 3 - 1) * self.charWidth + GAP + self.xposEnd = self.xposAscii + self.charWidth * BYTES_PER_LINE + GAP + self.setMinimumWidth(self.xposEnd) + if self.isVisible(): + sbw = self.scrollArea.verticalScrollBar().width() + self.scrollArea.setMinimumWidth(self.xposEnd + sbw + 5) + r = len(self.Data) % BYTES_PER_LINE + r = 1 if r > 0 else 0 + self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + r) * self.charHeight + 4) + self.scrollArea.setMinimumHeight(self.charHeight * 8) + self.update() + def showEvent(self, e): + self.adjust() + super().showEvent(e) + def setData(self, d): + self.data = bytearray(d) + self.originalData = bytearray(d) + self.adjust() + self.setCursorPosition(0) + Data = property(lambda self: self.data, setData) + +class HexEdit(QScrollArea): + def __init__(self): + super().__init__() + self.bv = BinViewer(self) + self.setWidget(self.bv) + self.setWidgetResizable(True) + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + self.setFocusPolicy(Qt.NoFocus) + +class HexEditor(QMainWindow): + def __init__(self): + super().__init__() + basedir = os.path.dirname(__file__) + uic.loadUi(os.path.join(basedir, 'hexeditor.ui'), baseinstance=self) + self.he = HexEdit() + self.setCentralWidget(self.he) + self.actionOpen.triggered.connect(self.doOpen) + self.actionSave.triggered.connect(self.doSave) + self.actionSaveAs.triggered.connect(self.doSaveAs) + self.fileName = None + self.updateControls() + def updateControls(self): + s = True if self.fileName else False + self.actionSave.setEnabled(s) + self.actionSaveAs.setEnabled(s) + def doOpen(self): + filename = QFileDialog.getOpenFileName(self) + if filename: + with open(filename, 'rb') as f: + self.he.bv.Data = f.read() + self.fileName = filename + self.updateControls() + def doSave(self): + self.updateControls() + def doSaveAs(self): + filename = QFileDialog.getSaveFileName(self) + if filename: + with open(filename, 'wb') as f: + f.write(self.he.bv.Data) + self.fileName = filename + self.updateControls() + +if __name__ == '__main__': + app = QApplication(sys.argv) + he = HexEditor() + he.show() + #he.bv.Data = bytearray(range(100)) * 8 + b'x' + app.exec() + diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/hexeditor.ui --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/hexeditor.ui Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,78 @@ + + + MainWindow + + + + 0 + 0 + 617 + 503 + + + + HexEditor + + + + + + 0 + 0 + 617 + 25 + + + + + File + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + Open + + + Opens a file for editing + + + Ctrl+O + + + + + Save + + + Ctrl+S + + + + + Save As + + + + + + diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/arrow.png Binary file python/ide/icons/arrow.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/chip.png Binary file python/ide/icons/chip.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/error.png Binary file python/ide/icons/error.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/functionicon.png Binary file python/ide/icons/functionicon.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/hardware.png Binary file python/ide/icons/hardware.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/info.png Binary file python/ide/icons/info.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/logo.png Binary file python/ide/icons/logo.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/variableicon.png Binary file python/ide/icons/variableicon.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/icons/warning.png Binary file python/ide/icons/warning.png has changed diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/ide.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/ide.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,338 @@ +#!/usr/bin/python + +import sys +import os +import logging +import traceback +import io + +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +# Compiler imports: +import ppci +from astviewer import AstViewer +from codeedit import CodeEdit +from logview import LogView as BuildOutput +from disasm import Disassembly +stutil = __import__('st-util') +import c3 +import zcc +import outstream + + +def handle_exception(tp, v, tb): + logging.critical(str(v)) + tb = traceback.format_tb(tb) + for i in tb: + logging.critical(i.strip()) + +sys.excepthook = handle_exception + +class BuildErrors(QTreeView): + sigErrorSelected = pyqtSignal(object) + + def __init__(self, parent=None): + super(BuildErrors, self).__init__(parent) + model = QStandardItemModel() + self.setModel(model) + self.clicked.connect(self.itemSelected) + self.errorIcon = QIcon('icons/error.png') + self.model = QStandardItemModel() + self.model.setHorizontalHeaderLabels(['Message', 'Row', 'Column']) + self.header().setStretchLastSection(True) + self.setModel(self.model) + + def setErrorList(self, errorlist): + c = self.model.rowCount() + self.model.removeRows(0, c) + for e in errorlist: + item = QStandardItem(self.errorIcon, str(e.msg)) + item.setData(e) + row = str(e.loc.row) if e.loc else '' + irow = QStandardItem(row) + irow.setData(e) + col = str(e.loc.col) if e.loc else '' + icol = QStandardItem(col) + icol.setData(e) + self.model.appendRow([item, irow, icol]) + for i in range(3): + self.resizeColumnToContents(i) + + def itemSelected(self, index): + if not index.isValid(): + return + item = self.model.itemFromIndex(index) + err = item.data() + self.sigErrorSelected.emit(err) + + + +class AboutDialog(QDialog): + def __init__(self, parent=None): + super(AboutDialog, self).__init__(parent) + self.setWindowTitle('About') + l = QVBoxLayout(self) + txt = QTextEdit(self) + txt.setReadOnly(True) + with open(os.path.join('..', 'readme.rst'), 'r') as f: + aboutText = f.read() + txt.append(aboutText) + l.addWidget(txt) + but = QPushButton('OK') + but.setDefault(True) + but.clicked.connect(self.close) + l.addWidget(but) + + +class Ide(QMainWindow): + def __init__(self, parent=None): + super(Ide, self).__init__(parent) + self.to_open_files = [] + self.logger = logging.getLogger('ide') + + self.setWindowTitle('LCFOS IDE') + icon = QIcon('icons/logo.png') + self.setWindowIcon(icon) + + # Create menus: + mb = self.menuBar() + self.fileMenu = mb.addMenu('File') + self.viewMenu = mb.addMenu('View') + self.helpMenu = mb.addMenu('Help') + + # Create mdi area: + self.mdiArea = QMdiArea() + self.mdiArea.setViewMode(QMdiArea.TabbedView) + self.mdiArea.setTabsClosable(True) + self.mdiArea.setTabsMovable(True) + self.setCentralWidget(self.mdiArea) + + # Create components: + def addComponent(name, widget): + dw = QDockWidget(name) + dw.setWidget(widget) + dw.setObjectName(name) + self.addDockWidget(Qt.RightDockWidgetArea, dw) + self.viewMenu.addAction(dw.toggleViewAction()) + return widget + + self.buildOutput = addComponent('Build output', BuildOutput()) + self.astViewer = addComponent('AST viewer', AstViewer()) + self.astViewer.sigNodeSelected.connect(lambda node: self.showLoc(node.loc)) + self.builderrors = addComponent('Build errors', BuildErrors()) + self.builderrors.sigErrorSelected.connect(lambda err: self.showLoc(err.loc)) + self.devxplr = addComponent('Device explorer', stutil.DeviceExplorer()) + self.regview = addComponent('Registers', stutil.RegisterView()) + self.memview = addComponent('Memory', stutil.MemoryView()) + self.disasm = addComponent('Disasm', Disassembly()) + self.ctrlToolbar = stutil.DebugToolbar() + self.addToolBar(self.ctrlToolbar) + self.ctrlToolbar.setObjectName('debugToolbar') + self.devxplr.deviceSelected.connect(self.regview.mdl.setDevice) + self.ctrlToolbar.statusChange.connect(self.memview.refresh) + self.devxplr.deviceSelected.connect(self.memview.setDevice) + self.devxplr.deviceSelected.connect(self.ctrlToolbar.setDevice) + self.ctrlToolbar.statusChange.connect(self.regview.refresh) + self.ctrlToolbar.codePosition.connect(self.pointCode) + + # About dialog: + self.aboutDialog = AboutDialog() + self.aboutDialog.setWindowIcon(icon) + + # Create actions: + def addMenuEntry(name, menu, callback, shortcut=None): + a = QAction(name, self) + menu.addAction(a) + a.triggered.connect(callback) + if shortcut: + a.setShortcut(shortcut) + + addMenuEntry("New", self.fileMenu, self.newFile, shortcut=QKeySequence(QKeySequence.New)) + addMenuEntry("Open", self.fileMenu, self.openFile, shortcut=QKeySequence(QKeySequence.Open)) + addMenuEntry("Save", self.fileMenu, self.saveFile, shortcut=QKeySequence(QKeySequence.Save)) + addMenuEntry("Build", self.fileMenu, self.buildFile, shortcut=QKeySequence("F7")) + addMenuEntry("Build and flash", self.fileMenu, self.buildFileAndFlash, shortcut=QKeySequence("F8")) + + self.helpAction = QAction('Help', self) + self.helpAction.setShortcut(QKeySequence('F1')) + self.helpMenu.addAction(self.helpAction) + addMenuEntry('About', self.helpMenu, self.aboutDialog.open) + + addMenuEntry('Cascade windows', self.viewMenu, self.mdiArea.cascadeSubWindows) + addMenuEntry('Tile windows', self.viewMenu, self.mdiArea.tileSubWindows) + sb = self.statusBar() + + # Load settings: + self.settings = QSettings('windelsoft', 'lcfoside') + self.loadSettings() + self.diag = ppci.DiagnosticsManager() + self.c3front = c3.Builder(self.diag) + + # File handling: + def newFile(self): + self.newCodeEdit() + + def openFile(self): + filename = QFileDialog.getOpenFileName(self, "Open C3 file...", "*.c3", + "C3 source files (*.c3)") + if filename: + self.loadFile(filename) + + def saveFile(self): + ac = self.activeMdiChild() + if ac: + ac.save() + + def loadFile(self, filename): + ce = self.newCodeEdit() + try: + with open(filename) as f: + ce.Source = f.read() + ce.FileName = filename + except Exception as e: + print('exception opening file', e) + + # MDI: + def newCodeEdit(self): + ce = CodeEdit() + ce.textChanged.connect(self.parseFile) + w = self.mdiArea.addSubWindow(ce) + self.mdiArea.setActiveSubWindow(w) + ce.showMaximized() + return ce + + def activeMdiChild(self): + aw = self.mdiArea.activeSubWindow() + if aw: + return aw.widget() + + def findMdiChild(self, filename): + for wid in self.allChildren(): + if wid.filename == filename: + return wid + + def allChildren(self): + return [w.widget() for w in self.mdiArea.subWindowList()] + + # Settings: + def loadSettings(self): + if self.settings.contains('mainwindowstate'): + self.restoreState(self.settings.value('mainwindowstate')) + if self.settings.contains('mainwindowgeometry'): + self.restoreGeometry(self.settings.value('mainwindowgeometry')) + if self.settings.contains('lastfiles'): + lfs = self.settings.value('lastfiles') + if lfs: + self.to_open_files.extend(lfs) + + def showEvent(self, ev): + super().showEvent(ev) + while self.to_open_files: + fn = self.to_open_files.pop(0) + self.loadFile(fn) + + def closeEvent(self, ev): + self.settings.setValue('mainwindowstate', self.saveState()) + self.settings.setValue('mainwindowgeometry', self.saveGeometry()) + ac = self.activeMdiChild() + lfs = [ce.FileName for ce in self.allChildren() if ce.FileName] + self.settings.setValue('lastfiles', lfs) + ev.accept() + + # Error handling: + def nodeSelected(self, node): + self.showLoc(node.loc) + + def showLoc(self, loc): + ce = self.activeMdiChild() + if not ce: + return + if loc: + ce.setRowCol(loc.row, loc.col) + ce.setFocus() + + def pointCode(self, p): + # Lookup pc in debug infos: + loc = None + print(p) + self.disasm.showPos(p) + if hasattr(self, 'debugInfo'): + for di in self.debugInfo: + if di.address > p: + loc = di.info + break + if loc: + ce = self.activeMdiChild() + if ce: + ce.ic.arrow = loc + self.showLoc(loc) + + # Build recepy: + def parseFile(self): + self.logger.info('Parsing!') + ce = self.activeMdiChild() + if not ce: + return + self.diag.clear() + pkg = self.c3front.parse(ce.Source) + + # Set errors: + self.builderrors.setErrorList(self.diag.diags) + ce.setErrors(self.diag.diags) + self.astViewer.setAst(pkg) + if pkg: + c3.AstPrinter().printAst(pkg) + self.logger.info('Done!') + + def buildFile(self): + ce = self.activeMdiChild() + if not ce: + return + fn = ce.FileName + self.diag.clear() + outs = outstream.TextOutputStream() + if not zcc.zcc([io.StringIO(ce.Source)], [], outs, self.diag): + # Set errors: + self.builderrors.setErrorList(self.diag.diags) + ce.setErrors(self.diag.diags) + return + + def buildFileAndFlash(self): + ce = self.activeMdiChild() + if not ce: + return + fn = ce.FileName + self.diag.clear() + outs = outstream.TextOutputStream() + imps = [open(ce.FileName, 'r') for ce in self.allChildren() if ce.FileName and ce.FileName != fn] + if not zcc.zcc([open(fn, 'r')], imps, outs, self.diag): + # Set errors: + self.builderrors.setErrorList(self.diag.diags) + ce.setErrors(self.diag.diags) + return + + outs.dump() + code_s = outs.getSection('code') + self.disasm.dm.setInstructions(code_s.instructions) + self.debugInfo = code_s.debugInfos() + if self.ctrlToolbar.device: + logging.info('Flashing stm32f4 discovery') + bts = code_s.to_bytes() + self.ctrlToolbar.device.writeFlash(0x08000000, bts) + stl = self.ctrlToolbar.device.iface + stl.reset() + stl.halt() + stl.run() + logging.info('Done!') + else: + self.logger.warning('Not connected to device, skipping flash') + + +if __name__ == '__main__': + logging.basicConfig(format=zcc.logformat, level=logging.DEBUG) + app = QApplication(sys.argv) + ide = Ide() + ide.show() + ide.logger.info('IDE started') + app.exec_() diff -r bd2593de3ff8 -r 7b38782ed496 python/ide/logview.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ide/logview.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,80 @@ +#!/usr/bin/python + +import sys +import os +import logging +import datetime + +from PyQt4.QtGui import QApplication, QWidget, QTableView, QVBoxLayout +from PyQt4.QtGui import QHeaderView +from PyQt4.QtCore import Qt +from PyQt4.QtCore import QAbstractTableModel + +def formatTime(t): + t2 = datetime.datetime.fromtimestamp(t) + return t2.strftime('%H:%M:%S') + +class LogModel(QAbstractTableModel): + def __init__(self): + super().__init__() + self.entries = [] + self.headers = ['Time', 'Level', 'Logger', 'Message'] + self.txts = [] + self.txts.append(lambda e: str(formatTime(e.created))) + self.txts.append(lambda e: str(e.levelname)) + self.txts.append(lambda e: str(e.name)) + self.txts.append(lambda e: str(e.msg)) + + def rowCount(self, parent): + return len(self.entries) + + def columnCount(self, parent): + return len(self.headers) + + def data(self, index, role): + if not index.isValid(): + return + row, col = index.row(), index.column() + if role == Qt.DisplayRole: + le = self.entries[row] + return self.txts[col](le) + + def headerData(self, section, orientation, role): + if orientation == Qt.Horizontal and role == Qt.DisplayRole: + return self.headers[section] + + def newLog(self, x): + self.entries.append(x) + self.modelReset.emit() + + +class LogView(QWidget): + """ Log view component """ + def __init__(self, parent=None): + super().__init__(parent) + l = QVBoxLayout(self) + self.tv = QTableView(self) + self.tv.horizontalHeader().setStretchLastSection(True) + l.addWidget(self.tv) + self.lm = LogModel() + self.tv.setModel(self.lm) + + class MyHandler(logging.Handler): + def emit(self2, x): + self.lm.newLog(x) + self.tv.scrollToBottom() + for i in range(3): + self.tv.resizeColumnToContents(i) + + logging.getLogger().addHandler(MyHandler()) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + lv = LogView() + lv.show() + lv.resize(600, 200) + logging.error('Error!!!') + logging.warn('Warn here!') + app.exec_() + diff -r bd2593de3ff8 -r 7b38782ed496 python/instructionselector.py --- a/python/instructionselector.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -import ir -import irmach -from irmach import AbstractInstruction as makeIns -import target - -def genTemps(): - n = 900 - while True: - yield ir.Temp('t{}'.format(n)) - n = n + 1 - - -class InstructionSelector: - """ - Base instruction selector. This class must be overridden by - backends. - """ - def __init__(self): - self.temps = genTemps() - - def newTmp(self): - return self.temps.__next__() - - def munchFunction(self, f, frame): - # Entry point for instruction selection - assert isinstance(f, ir.Function) - self.targets = {} - # Enter a frame per function: - self.frame = frame - # First define labels: - for bb in f.Blocks: - itgt = makeIns(target.Label(bb.name)) - self.targets[bb] = itgt - # Generate code for all blocks: - for bb in f.Blocks: - self.emit2(self.targets[bb]) - for i in bb.Instructions: - self.munchStm(i) - self.munchStm(ir.Move(self.frame.rv, f.return_value)) - - def move(self, dst, src): - raise NotImplementedError('Not target implemented') - - def emit(self, *args, **kwargs): - """ Abstract instruction emitter """ - i = makeIns(*args, **kwargs) - return self.emit2(i) - - def emit2(self, i): - self.frame.instructions.append(i) - return i - - def munchStm(self, s): - """ Implement this in the target specific back-end """ - raise NotImplementedError() - - def munchExpr(self, e): - """ Implement this in the target specific back-end """ - raise NotImplementedError() - diff -r bd2593de3ff8 -r 7b38782ed496 python/integration_methods.py --- a/python/integration_methods.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,205 +0,0 @@ -import sys -from random import random -import numpy as np -import pylab -import time -import scipy.integrate - -""" - This script compares different methods to solve an ODE. - - The solved system consists of: - y_dot = f(y, t, p) - y0 - - where - y: the state vector of the system - y0: the initial state of the system - y_dot: the derivatives of the state vector - f: the function that returns the derivatives. - t: the time instant - p: the parameters of the system -""" - -def func(y, t, parameters): - """ - The example system is a bouncing point mass on a hunt-cossley surface. - State vector: - y[0] = height - y[1] = vertical momentum - - y_dot[0] = velocity - y_dot[1] = force - """ - # Step 1: extract the states into variables: - h = y[0] - p = y[1] - mass = parameters[0] - Kp_floor = parameters[1] - Kd_floor = parameters[2] - - # Step 2: Calculate model: - v = p / mass - - # Ground reaction force: - if h > 0: - F = 0.0 - else: - F = -h * Kp_floor - - # Gravity: - F += -9.81 * mass - y_dot = np.array([v, F], dtype=np.float) - return y_dot - -parameters = np.array([3, 50000, 3000], dtype=np.float) -y0 = np.array([1, 0], dtype=np.float) # Start at 1 meter, with 0 momentum - -class SCIPY: - def __init__(self, dt): - self.dt = dt - def name(self): - return "scipy.integrate" - def integrate(self, f, y0, parameters, endtime): - timevector = np.arange(0.0, endtime, self.dt) - states = scipy.integrate.odeint(f, y0, timevector, args=(parameters,)) - return timevector, states - -class RK4: - def __init__(self, dt): - self.dt = dt - - def name(self): - return "RK4" - def integrate(self, f, y0, parameters, endtime): - print(y0, parameters) - t = 0.0 - states = [] - timevector = [] - state = y0 - states.append(state) - timevector.append(t) - while t < endtime: - #### Runge Kutta integration: - k1 = func(state, t, parameters) - k2 = func(state + 0.5*self.dt*k1, t, parameters) - k3 = func(state + 0.5*self.dt*k1, t, parameters) - k4 = func(state + self.dt*k3, t, parameters) - newstate = state + (self.dt/6.0)*(k1+2*k2+2*k3+k4) - - t += self.dt - state = newstate - - states.append(state) - timevector.append(t) - - return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) - - -class BDFfixed: - def __init__(self, order): - self.order = order - def name(self): - return "BDF" - def integrate(self, f, y0, parameters, endtime): - timevector = [] - states = [] - timevector.append(0.0) - states.append(y0) - t = 0.0 - h = 0.01 - state = y0 - while t < endtime: - if len(states) < 4: - k1 = func(state, t, parameters) - k2 = func(state + 0.5*h*k1, t, parameters) - k3 = func(state + 0.5*h*k1, t, parameters) - k4 = func(state + h*k3, t, parameters) - newstate = state + (h/6.0)*(k1+2*k2+2*k3+k4) - state = newstate - t += h - timevector.append(t) - states.append(state) - else: - t += h - if np.max(state) > 10: - break - hyn = (11.0/6.0)*states[-1] + (-3)*states[-2] + (3/2)*states[-3] + (-1/3)*states[-4] - state = state + hyn - timevector.append(t) - states.append(state) - - return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) - -class WODE: - def __init__(self): - pass - def integrate(self, f, y0, parameters, endtime): - timevector = [] - states = [] - timevector.append(0.0) - states.append(y0) - return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) - -class DOPRI45: - def __init__(self): - pass - def name(self): - return "DOPRI" - def integrate(self, f, y0, parameters, endtime): - timevector = [] - states = [] - timevector.append(0.0) - states.append(y0) - y = y0 - t = 0.0 - - h = 0.01 - iteration = 0 - while t < endtime: - k1 = h*f(y, t, parameters) - k2 = h*f(y + (1.0/5.0)*k1, t + (1.0/5.0)*h, parameters) - k3 = h*f(y + (3.0/40.0)*k1 + (9.0/40.0)*k2, t + (3.0/10.0)*h, parameters) - k4 = h*f(y + (44.0/45.0)*k1 - (56.0/15.0)*k2 + (32.0/9.0)*k3, t + (4.0/5.0)*h, parameters) - k5 = h*f(y + (19372.0/6561.0)*k1 - (25360.0/2187.0)*k2 + (64448.0/6561.0)*k3 - (212.0/729.0)*k4, t + (8.0/9.0)*h, parameters) - k6 = h*f(y + (9017.0/3168.0)*k1 - (355.0/33.0)*k2 - (46732.0/5247.0)*k3 + (49.0/176.0)*k4 - (5103.0/18656.0)*k5, t + h, parameters) - k7 = h*f(y + (35.0/384.0)*k1 + (500.0/1113.0)*k3 + (125.0/192.0)*k4 - (2187.0/6784.0)*k5 + (11.0/84.0)*k6, t + h, parameters) - - - y_next = y + (35.0/384.0)*k1 + (500.0/1113.0)*k3 + (125.0/192.0)*k4 - (2187.0/6784.0)*k5 + (11.0/84.0)*k6 - z_next = y + (5179.0/57600.0)*k1 + (7571.0/16695.0)*k3 + (393.0/640.0)*k4 - (92097.0/339200.0)*k5 + (187.0/2100.0)*k6 + (1.0/40.0)*k7 - error = np.linalg.norm(y_next - z_next) - #print(error, t) - eps = 0.01 - if error < eps: - y = y_next - t = t + h - timevector.append(t) - states.append(y) - - s = ((eps*h)/(2*error)) ** (1.0/5.0) - h = s * h - if h < 1e-5: - h = 1e-5 - iteration += 1 - if iteration > 10000: - break - - return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) - -rk4 = RK4(0.01) -sp = SCIPY(0.01) -wode = BDFfixed(4) -dopri = DOPRI45() -methods = [rk4, sp, dopri] - -pylab.figure() -pylab.hold(True) -for method in methods: - t, s = method.integrate(func, y0, parameters, 10) - print(t.shape, s.shape) - pylab.plot(t, s[:,0], 'x-', label=method.name()) - -pylab.legend() -pylab.show() - diff -r bd2593de3ff8 -r 7b38782ed496 python/isa/openrisc.lidl --- a/python/isa/openrisc.lidl Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ - -// Openrisc description in lidl (lcfos isa description language) - -// Register storage: -storage r { - width: 32 - size: 32 -} - - -instruction add { - encoding: '111111111DDDDDDAAAAAABBBBBB' - semantics: D = A + B -} - - -// ... - -instruction push { - encoding: '' - semantics: { - sp = X - sp = sp - 4 - } -} - diff -r bd2593de3ff8 -r 7b38782ed496 python/iso9660.py --- a/python/iso9660.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -import argparse - -__doc__ = """ - ISO 9660 filesystem utility. -""" - - -class VolumeDescriptor: - @classmethod - def FromData(cls, d): - ty = d[0] - Id = d[1:6] - assert Id == 'CD001'.encode('ascii') - ver = d[6] - assert ver == 1 - cls = vol_desc_types[ty] - return cls(d) - - -vol_desc_types = {} -def vol_type(t): - def reg_func(cls): - vol_desc_types[t] = cls - return cls - return reg_func - - -@vol_type(0) -class BootRecordVolumeDescriptor(VolumeDescriptor): - def __init__(self, d): - boot_sys_id = d[7:39] - boot_id = d[39:71] - print(boot_sys_id) - print(boot_id) - - -@vol_type(1) -class PrimaryVolumeDescriptor(VolumeDescriptor): - def __init__(self, d): - sys_id = d[8:40] - vol_id = d[40:72] - print(sys_id) - print(vol_id) - - -@vol_type(255) -class VolumeDescriptorTerminator(VolumeDescriptor): - def __init__(self, d): - pass - - -class ISOfs: - def __init__(self): - self.vol_descriptors = [] - - def read(self, f): - # System area: - self.system_area = f.read(16 * 2048) - while True: - d = f.read(2048) - desc = VolumeDescriptor.FromData(d) - self.vol_descriptors.append(desc) - if type(desc) is VolumeDescriptorTerminator: - break - - def dump(self): - for vd in self.vol_descriptors: - print(vd) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('filename') - args = parser.parse_args() - fs = ISOfs() - with open(args.filename, 'rb') as f: - fs.read(f) - fs.dump() - - diff -r bd2593de3ff8 -r 7b38782ed496 python/logview.py --- a/python/logview.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -#!/usr/bin/python - -import sys -import os -import logging -import datetime - -from PyQt4.QtGui import QApplication, QWidget, QTableView, QVBoxLayout -from PyQt4.QtGui import QHeaderView -from PyQt4.QtCore import Qt -from PyQt4.QtCore import QAbstractTableModel - -def formatTime(t): - t2 = datetime.datetime.fromtimestamp(t) - return t2.strftime('%H:%M:%S') - -class LogModel(QAbstractTableModel): - def __init__(self): - super().__init__() - self.entries = [] - self.headers = ['Time', 'Level', 'Logger', 'Message'] - self.txts = [] - self.txts.append(lambda e: str(formatTime(e.created))) - self.txts.append(lambda e: str(e.levelname)) - self.txts.append(lambda e: str(e.name)) - self.txts.append(lambda e: str(e.msg)) - - def rowCount(self, parent): - return len(self.entries) - - def columnCount(self, parent): - return len(self.headers) - - def data(self, index, role): - if not index.isValid(): - return - row, col = index.row(), index.column() - if role == Qt.DisplayRole: - le = self.entries[row] - return self.txts[col](le) - - def headerData(self, section, orientation, role): - if orientation == Qt.Horizontal and role == Qt.DisplayRole: - return self.headers[section] - - def newLog(self, x): - self.entries.append(x) - self.modelReset.emit() - - -class LogView(QWidget): - """ Log view component """ - def __init__(self, parent=None): - super().__init__(parent) - l = QVBoxLayout(self) - self.tv = QTableView(self) - self.tv.horizontalHeader().setStretchLastSection(True) - l.addWidget(self.tv) - self.lm = LogModel() - self.tv.setModel(self.lm) - - class MyHandler(logging.Handler): - def emit(self2, x): - self.lm.newLog(x) - self.tv.scrollToBottom() - for i in range(3): - self.tv.resizeColumnToContents(i) - - logging.getLogger().addHandler(MyHandler()) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - lv = LogView() - lv.show() - lv.resize(600, 200) - logging.error('Error!!!') - logging.warn('Warn here!') - app.exec_() - diff -r bd2593de3ff8 -r 7b38782ed496 python/msp430.py --- a/python/msp430.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -from target import Register, Instruction, Target -from asmnodes import ASymbol, ANumber -from ppci import CompilerError -import struct, types - -# Create the target class (singleton): -msp430target = Target("MSP430") - -REGISTER_MODE = 1 -SYMBOLIC_MODE = 3 -ABSOLUTE_MODE = 4 -#TODO: add more modes! -IMMEDIATE_MODE = 7 - -# Target description for the MSP430 processor - -class MSP430Reg(Register): - def __init__(self, num, name): - super().__init__(name) - self.num = num - -# 8 bit registers: -PCB = MSP430Reg(0, 'r0') -rpc = PCB -r11 = MSP430Reg(11, 'r11') -r12 = MSP430Reg(12, 'r12') -r13 = MSP430Reg(13, 'r13') -r14 = MSP430Reg(14, 'r14') -r15 = MSP430Reg(15, 'r15') - -class MSP430Mem: - pass - -msp430target.registers.append(r11) -msp430target.registers.append(r12) -msp430target.registers.append(r13) -msp430target.registers.append(r14) -msp430target.registers.append(r15) - -# .. etc - -#GR8 = RegisterClass((PCB, R15B)) - -class MSP430Operand: - def __init__(self, mode, param): - self.mode = mode - self.param = param - def regField(self): - if self.mode == REGISTER_MODE: - return self.param - elif self.mode == IMMEDIATE_MODE: - return rpc.num - def asField(self): - if self.mode == REGISTER_MODE: - return 0 - elif self.mode == IMMEDIATE_MODE: - return 3 - def adField(self): - if self.mode == REGISTER_MODE: - return 0 - elif self.mode == IMMEDIATE_MODE: - raise CompilerError('Cannot use immediate mode for destination operand') - def extraBytes(self): - if self.mode == IMMEDIATE_MODE: - return pack_ins(self.param) - return bytes() - - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - # try to map to register: - regs = {} - for r in msp430target.registers: - regs[r.name] = r - if vop.name in regs: - reg = regs[vop.name] - return cls(REGISTER_MODE, reg.num) - elif type(vop) is ANumber: - # Immediate mode: - return cls(IMMEDIATE_MODE, vop.number) - -def pack_ins(h): - return struct.pack(' 0: + return 0 + if parent.isValid(): + block = parent.internalPointer() + if hasattr(block, 'subModel'): + return len(block.subModel.blocks) + else: + return 0 + else: + return len(self.rootDiagram.blocks) + def columnCount(self, parent): + return 2 + +class LibraryWidget(QListView): + def __init__(self): + super(LibraryWidget, self).__init__(None) + self.libraryModel = LibraryModel(self) + self.libraryModel.setColumnCount(1) + # Create an icon with an icon: + pixmap = QPixmap(60, 60) + pixmap.fill() + painter = QPainter(pixmap) + painter.fillRect(10, 10, 40, 40, Qt.blue) + painter.setBrush(Qt.yellow) + painter.drawEllipse(20, 20, 20, 20) + painter.end() + # Fill library: + for name in ['CodeBlock:codeBlock', 'DiagramBlock:submod', 'Block:blk']: + self.libraryModel.appendRow(QStandardItem(QIcon(pixmap), name)) + self.setModel(self.libraryModel) + self.setViewMode(self.IconMode) + self.setDragDropMode(self.DragOnly) + +def warning(txt): + QMessageBox.warning(None, "Warning", txt) + +def loadModel(filename): + try: + m = ModelHierarchyModel() + with open(filename, 'r') as f: data = f.read() + m.filename = filename + m.Dict = json.loads(data) + return m + except KeyError: + warning('Corrupt model: {0}'.format(filename)) + except ValueError: + warning('Corrupt model: {0}'.format(filename)) + except FileNotFoundError: + warning('File [{0}] not found'.format(filename)) + +class Main(QMainWindow): + def __init__(self): + super(Main, self).__init__(None) + self.editor = EditorGraphicsView() + self.setCentralWidget(self.editor) + self.setWindowTitle("Diagram editor") + def buildIcon(b64): + icon = base64.decodestring(b64) + pm = QPixmap() + pm.loadFromData(icon) + return QIcon(pm) + toolbar = self.addToolBar('Tools') + toolbar.setObjectName('Tools') + def act(name, shortcut, callback, icon=None): + a = QAction(icon, name, self) if icon else QAction(name, self) + a.setShortcuts(shortcut) + a.triggered.connect(callback) + toolbar.addAction(a) + act('New', QKeySequence.New, self.editor.newModel, buildIcon(newicon)) + act('Save', QKeySequence.Save, self.editor.save, buildIcon(saveicon)) + act('Load', QKeySequence.Open, self.editor.load, buildIcon(loadicon)) + act('Full screen', QKeySequence("F11"), self.toggleFullScreen) + act('Fit in view', QKeySequence("F8"), self.editor.zoomAll) + act('Go up', QKeySequence(Qt.Key_Up), self.editor.goUp) + act('Model code', QKeySequence("F7"), self.editor.showCode) + def addDock(name, widget): + dock = QDockWidget(name, self) + dock.setObjectName(name) + dock.setWidget(widget) + self.addDockWidget(Qt.LeftDockWidgetArea, dock) + addDock('Library', LibraryWidget()) + addDock('Model tree', self.editor.treeView) + self.settings = QSettings('windelsoft', 'diagrameditor') + self.loadSettings() + def toggleFullScreen(self): + self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) + self.editor.zoomAll() + def loadSettings(self): + if self.settings.contains('mainwindowstate'): + self.restoreState(self.settings.value('mainwindowstate')) + if self.settings.contains('mainwindowgeometry'): + self.restoreGeometry(self.settings.value('mainwindowgeometry')) + if self.settings.contains('openedmodel'): + modelfile = self.settings.value('openedmodel') + self.editor.model = loadModel(modelfile) + def closeEvent(self, ev): + self.settings.setValue('mainwindowstate', self.saveState()) + self.settings.setValue('mainwindowgeometry', self.saveGeometry()) + if self.editor.model and self.editor.model.filename: + self.settings.setValue('openedmodel', self.editor.model.filename) + # TODO: ask for save of opened files + else: + self.settings.remove('openedmodel') + ev.accept() + +if __name__ == '__main__': + if sys.version_info.major != 3: + print('Please use python 3.x') + sys.exit(1) + app = QApplication(sys.argv) + main = Main() + main.show() + app.exec_() + diff -r bd2593de3ff8 -r 7b38782ed496 python/other/integration_methods.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/other/integration_methods.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,205 @@ +import sys +from random import random +import numpy as np +import pylab +import time +import scipy.integrate + +""" + This script compares different methods to solve an ODE. + + The solved system consists of: + y_dot = f(y, t, p) + y0 + + where + y: the state vector of the system + y0: the initial state of the system + y_dot: the derivatives of the state vector + f: the function that returns the derivatives. + t: the time instant + p: the parameters of the system +""" + +def func(y, t, parameters): + """ + The example system is a bouncing point mass on a hunt-cossley surface. + State vector: + y[0] = height + y[1] = vertical momentum + + y_dot[0] = velocity + y_dot[1] = force + """ + # Step 1: extract the states into variables: + h = y[0] + p = y[1] + mass = parameters[0] + Kp_floor = parameters[1] + Kd_floor = parameters[2] + + # Step 2: Calculate model: + v = p / mass + + # Ground reaction force: + if h > 0: + F = 0.0 + else: + F = -h * Kp_floor + + # Gravity: + F += -9.81 * mass + y_dot = np.array([v, F], dtype=np.float) + return y_dot + +parameters = np.array([3, 50000, 3000], dtype=np.float) +y0 = np.array([1, 0], dtype=np.float) # Start at 1 meter, with 0 momentum + +class SCIPY: + def __init__(self, dt): + self.dt = dt + def name(self): + return "scipy.integrate" + def integrate(self, f, y0, parameters, endtime): + timevector = np.arange(0.0, endtime, self.dt) + states = scipy.integrate.odeint(f, y0, timevector, args=(parameters,)) + return timevector, states + +class RK4: + def __init__(self, dt): + self.dt = dt + + def name(self): + return "RK4" + def integrate(self, f, y0, parameters, endtime): + print(y0, parameters) + t = 0.0 + states = [] + timevector = [] + state = y0 + states.append(state) + timevector.append(t) + while t < endtime: + #### Runge Kutta integration: + k1 = func(state, t, parameters) + k2 = func(state + 0.5*self.dt*k1, t, parameters) + k3 = func(state + 0.5*self.dt*k1, t, parameters) + k4 = func(state + self.dt*k3, t, parameters) + newstate = state + (self.dt/6.0)*(k1+2*k2+2*k3+k4) + + t += self.dt + state = newstate + + states.append(state) + timevector.append(t) + + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + + +class BDFfixed: + def __init__(self, order): + self.order = order + def name(self): + return "BDF" + def integrate(self, f, y0, parameters, endtime): + timevector = [] + states = [] + timevector.append(0.0) + states.append(y0) + t = 0.0 + h = 0.01 + state = y0 + while t < endtime: + if len(states) < 4: + k1 = func(state, t, parameters) + k2 = func(state + 0.5*h*k1, t, parameters) + k3 = func(state + 0.5*h*k1, t, parameters) + k4 = func(state + h*k3, t, parameters) + newstate = state + (h/6.0)*(k1+2*k2+2*k3+k4) + state = newstate + t += h + timevector.append(t) + states.append(state) + else: + t += h + if np.max(state) > 10: + break + hyn = (11.0/6.0)*states[-1] + (-3)*states[-2] + (3/2)*states[-3] + (-1/3)*states[-4] + state = state + hyn + timevector.append(t) + states.append(state) + + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + +class WODE: + def __init__(self): + pass + def integrate(self, f, y0, parameters, endtime): + timevector = [] + states = [] + timevector.append(0.0) + states.append(y0) + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + +class DOPRI45: + def __init__(self): + pass + def name(self): + return "DOPRI" + def integrate(self, f, y0, parameters, endtime): + timevector = [] + states = [] + timevector.append(0.0) + states.append(y0) + y = y0 + t = 0.0 + + h = 0.01 + iteration = 0 + while t < endtime: + k1 = h*f(y, t, parameters) + k2 = h*f(y + (1.0/5.0)*k1, t + (1.0/5.0)*h, parameters) + k3 = h*f(y + (3.0/40.0)*k1 + (9.0/40.0)*k2, t + (3.0/10.0)*h, parameters) + k4 = h*f(y + (44.0/45.0)*k1 - (56.0/15.0)*k2 + (32.0/9.0)*k3, t + (4.0/5.0)*h, parameters) + k5 = h*f(y + (19372.0/6561.0)*k1 - (25360.0/2187.0)*k2 + (64448.0/6561.0)*k3 - (212.0/729.0)*k4, t + (8.0/9.0)*h, parameters) + k6 = h*f(y + (9017.0/3168.0)*k1 - (355.0/33.0)*k2 - (46732.0/5247.0)*k3 + (49.0/176.0)*k4 - (5103.0/18656.0)*k5, t + h, parameters) + k7 = h*f(y + (35.0/384.0)*k1 + (500.0/1113.0)*k3 + (125.0/192.0)*k4 - (2187.0/6784.0)*k5 + (11.0/84.0)*k6, t + h, parameters) + + + y_next = y + (35.0/384.0)*k1 + (500.0/1113.0)*k3 + (125.0/192.0)*k4 - (2187.0/6784.0)*k5 + (11.0/84.0)*k6 + z_next = y + (5179.0/57600.0)*k1 + (7571.0/16695.0)*k3 + (393.0/640.0)*k4 - (92097.0/339200.0)*k5 + (187.0/2100.0)*k6 + (1.0/40.0)*k7 + error = np.linalg.norm(y_next - z_next) + #print(error, t) + eps = 0.01 + if error < eps: + y = y_next + t = t + h + timevector.append(t) + states.append(y) + + s = ((eps*h)/(2*error)) ** (1.0/5.0) + h = s * h + if h < 1e-5: + h = 1e-5 + iteration += 1 + if iteration > 10000: + break + + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + +rk4 = RK4(0.01) +sp = SCIPY(0.01) +wode = BDFfixed(4) +dopri = DOPRI45() +methods = [rk4, sp, dopri] + +pylab.figure() +pylab.hold(True) +for method in methods: + t, s = method.integrate(func, y0, parameters, 10) + print(t.shape, s.shape) + pylab.plot(t, s[:,0], 'x-', label=method.name()) + +pylab.legend() +pylab.show() + diff -r bd2593de3ff8 -r 7b38782ed496 python/other/qtpropertyviewer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/other/qtpropertyviewer.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,103 @@ +from PyQt4.QtCore import * +from PyQt4.QtGui import * +import sys + +class QtPropertyModel(QAbstractTableModel): + def __init__(self): + super().__init__() + self.InspectedWidget = None + def getInspectedWidget(self): + return self.inspectedWidget + def setInspectedWidget(self, w): + self.inspectedWidget = w + if isinstance(self.inspectedWidget, QObject): + mo = self.inspectedWidget.metaObject() + self.metaprops = [mo.property(i) for i in range(mo.propertyCount())] + self.metaprops = sorted(self.metaprops, key=lambda mp: mp.name()) + else: + self.metaprops = [] + self.modelReset.emit() + InspectedWidget = property(getInspectedWidget, setInspectedWidget) + def rowCount(self, parent): + return len(self.metaprops) + def columnCount(self, parent): + return 2 + def headerData(self, section, orientation, role): + if orientation == Qt.Horizontal and role == Qt.DisplayRole: + if section == 0: + return 'Property' + elif section == 1: + return 'Value' + def data(self, index, role): + if index.isValid(): + row = index.row() + col = index.column() + metaprop = self.metaprops[row] + if role == Qt.DisplayRole: + propname = metaprop.name() + if col == 0: + return propname + elif col == 1: + if metaprop.isReadable(): + propval = metaprop.read(self.inspectedWidget) + return propval + return 'NOT READABLE' + return '{0}, {1}'.format(row, col) + elif role == Qt.BackgroundRole: + if col == 1: + if metaprop.isWritable(): + return QBrush(Qt.green) + else: + return QBrush(Qt.red) + elif role == Qt.CheckStateRole: + if col == 1: + val = metaprop.read(self.inspectedWidget) + if type(val) is bool: + val = Qt.Checked if val else Qt.Unchecked + return val + + def flags(self, index): + if index.isValid(): + row = index.row() + col = index.column() + metaprop = self.metaprops[row] + if col == 1 and metaprop.isWritable(): + val = metaprop.read(self.inspectedWidget) + if type(val) == bool: + return super().flags(index) | Qt.ItemIsEditable | Qt.ItemIsUserCheckable + else: + return super().flags(index) | Qt.ItemIsEditable + else: + return super().flags(index) + def setData(self, index, value, role): + if index.isValid(): + row = index.row() + col = index.column() + metaprop = self.metaprops[row] + if role == Qt.EditRole: + metaprop.write(self.inspectedWidget, value) + return True + elif role == Qt.CheckStateRole: + value = True if value == Qt.Checked else False + metaprop.write(self.inspectedWidget, value) + return True + else: + print('unknown role:', role) + return False + return False + +class QtPropertyViewer(QWidget): + """ + The binviewer consists of a hex view, a ascii view + and perhaps others.. + """ + def __init__(self): + super().__init__() + tableView = QTableView() + l = QVBoxLayout(self) + l.addWidget(tableView) + header = tableView.horizontalHeader() + header.setResizeMode(QHeaderView.ResizeToContents) + self.propertyModel = QtPropertyModel() + tableView.setModel(self.propertyModel) + diff -r bd2593de3ff8 -r 7b38782ed496 python/qtpropertyviewer.py --- a/python/qtpropertyviewer.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -from PyQt4.QtCore import * -from PyQt4.QtGui import * -import sys - -class QtPropertyModel(QAbstractTableModel): - def __init__(self): - super().__init__() - self.InspectedWidget = None - def getInspectedWidget(self): - return self.inspectedWidget - def setInspectedWidget(self, w): - self.inspectedWidget = w - if isinstance(self.inspectedWidget, QObject): - mo = self.inspectedWidget.metaObject() - self.metaprops = [mo.property(i) for i in range(mo.propertyCount())] - self.metaprops = sorted(self.metaprops, key=lambda mp: mp.name()) - else: - self.metaprops = [] - self.modelReset.emit() - InspectedWidget = property(getInspectedWidget, setInspectedWidget) - def rowCount(self, parent): - return len(self.metaprops) - def columnCount(self, parent): - return 2 - def headerData(self, section, orientation, role): - if orientation == Qt.Horizontal and role == Qt.DisplayRole: - if section == 0: - return 'Property' - elif section == 1: - return 'Value' - def data(self, index, role): - if index.isValid(): - row = index.row() - col = index.column() - metaprop = self.metaprops[row] - if role == Qt.DisplayRole: - propname = metaprop.name() - if col == 0: - return propname - elif col == 1: - if metaprop.isReadable(): - propval = metaprop.read(self.inspectedWidget) - return propval - return 'NOT READABLE' - return '{0}, {1}'.format(row, col) - elif role == Qt.BackgroundRole: - if col == 1: - if metaprop.isWritable(): - return QBrush(Qt.green) - else: - return QBrush(Qt.red) - elif role == Qt.CheckStateRole: - if col == 1: - val = metaprop.read(self.inspectedWidget) - if type(val) is bool: - val = Qt.Checked if val else Qt.Unchecked - return val - - def flags(self, index): - if index.isValid(): - row = index.row() - col = index.column() - metaprop = self.metaprops[row] - if col == 1 and metaprop.isWritable(): - val = metaprop.read(self.inspectedWidget) - if type(val) == bool: - return super().flags(index) | Qt.ItemIsEditable | Qt.ItemIsUserCheckable - else: - return super().flags(index) | Qt.ItemIsEditable - else: - return super().flags(index) - def setData(self, index, value, role): - if index.isValid(): - row = index.row() - col = index.column() - metaprop = self.metaprops[row] - if role == Qt.EditRole: - metaprop.write(self.inspectedWidget, value) - return True - elif role == Qt.CheckStateRole: - value = True if value == Qt.Checked else False - metaprop.write(self.inspectedWidget, value) - return True - else: - print('unknown role:', role) - return False - return False - -class QtPropertyViewer(QWidget): - """ - The binviewer consists of a hex view, a ascii view - and perhaps others.. - """ - def __init__(self): - super().__init__() - tableView = QTableView() - l = QVBoxLayout(self) - l.addWidget(tableView) - header = tableView.horizontalHeader() - header.setResizeMode(QHeaderView.ResizeToContents) - self.propertyModel = QtPropertyModel() - tableView.setModel(self.propertyModel) - diff -r bd2593de3ff8 -r 7b38782ed496 python/target.py --- a/python/target.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -from asmnodes import ASymbol, AInstruction, ANumber -from ppci import CompilerError - -""" - Base classes for defining a target -""" - -# Machine code interface: -class Operand: - """ Single machine operand """ - pass - -# standard immediates: - -class Imm8: - def __init__(self, imm): - assert imm < 256 - 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 - - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 128: - return cls(vop.number) - -class Imm3: - def __init__(self, imm): - assert imm < 8 - assert type(imm) is int - self.imm = imm - - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 8: - return cls(vop.number) - -class Imm32: - def __init__(self, imm): - assert imm < 2**32 - assert type(imm) is int - self.imm = imm - - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 2**32: - return cls(vop.number) - - -class LabelRef: - def __init__(self, name): - assert type(name) is str - self.name = name - - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - return cls(vop.name) - -class Instruction: - def encode(self): - raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self))) - def resolve(self, f): - pass - - -class Nop(Instruction): - """ Instruction that does nothing and has zero size """ - def encode(self): - return bytes() - - - -class PseudoInstruction(Instruction): - pass - - -class Label(PseudoInstruction): - def __init__(self, name): - self.name = name - self.address = 0 - - def __repr__(self): - return '{}:'.format(self.name) - - def encode(self): - return bytes() - - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - name = vop.name - return cls(name) - - -class Comment(PseudoInstruction): - def __init__(self, txt): - self.txt = txt - - def encode(self): - return bytes() - - def __repr__(self): - return '; {}'.format(self.txt) - - -class Alignment(PseudoInstruction): - def __init__(self, a): - self.align = a - - def __repr__(self): - return 'ALIGN({})'.format(self.align) - - def encode(self): - pad = [] - address = self.address - while (address % self.align) != 0: - address += 1 - pad.append(0) - return bytes(pad) - -class DebugInfo(PseudoInstruction): - def __init__(self, i): - self.info = i - - def __repr__(self): - return 'DebugInfo: {}'.format(self.info) - - def encode(self): - return bytes() - -class Register(Operand): - def __init__(self, name): - self.name = name - - -class Target: - def __init__(self, name, desc=''): - self.name = name - self.desc = desc - self.registers = [] - self.instructions = [] - - def instruction(self, cls): - """ Decorator function that registers an instruction to this target """ - self.addInstruction(cls) - return cls - - def check(self): - """ Check target """ - for i in self.instructions: - assert hasattr(i, 'mnemonic') - assert hasattr(i, 'operands'), str(i) - assert type(i.mnemonic) is str - assert type(i.operands) is tuple, str(i) - - def addInstruction(self, ins_class): - self.instructions.append(ins_class) - - def mapOperand(self, operand): - """ Try to map an operand to a target type """ - if type(operand) is ASymbol: - # Try to map to register: - regs = {} - for r in self.registers: - regs[r.name] = r - if operand.name in regs: - return regs[operand.name] - raise CompilerError('Cannot map {0}'.format(operand)) - - def mapInstruction(self, vi): - assert type(vi) is AInstruction - """ Map ast tree to real instruction for this target """ - - # map to real operands: - if vi.mnemonic.upper() == 'ALIGN' and len(vi.operands) == 1: - if type(vi.operands[0]) == ANumber: - return Alignment(vi.operands[0].number) - - # look for a suitable instruction - for ic in self.instructions: - if ic.mnemonic.upper() == vi.mnemonic.upper() and len(ic.operands) == len(vi.operands): - # Try to map operands to the correct operand types: - rops = [roptype.Create(vop) for roptype, vop in zip(ic.operands, vi.operands)] - - # Check if we succeeded: - 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)) - diff -r bd2593de3ff8 -r 7b38782ed496 python/target/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/__init__.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +from .basetarget import Nop, Instruction, Label, Target, Comment, Alignment +from .basetarget import Imm32, DebugInfo +#from .armtarget import armtarget +#from .msp430target import msp430target + +#target_list = [armtarget, msp430target] diff -r bd2593de3ff8 -r 7b38782ed496 python/target/armframe.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/armframe.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,219 @@ +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 + + +class ArmFrame(irmach.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.rv = ir.Temp('special_RV') + self.p1 = ir.Temp('special_P1') + self.p2 = ir.Temp('special_P2') + self.p3 = ir.Temp('special_P3') + self.p4 = ir.Temp('special_P4') + 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.locVars = {} + self.parMap = {} + # Literal pool: + self.constants = [] + + def argLoc(self, pos): + """ + Gets the function parameter location in IR-code format. + """ + if pos == 0: + return self.p1 + elif pos == 1: + return self.p2 + elif pos == 2: + return self.p3 + elif pos == 3: + return self.p4 + else: + raise NotImplementedError('No more than 4 parameters implemented') + + def allocVar(self, lvar): + if lvar not in self.locVars: + self.locVars[lvar] = self.stacksize + self.stacksize = self.stacksize + 4 + return self.locVars[lvar] + + def addConstant(self, value): + lab_name = '{}_literal_{}'.format(self.name, len(self.constants)) + self.constants.append((lab_name, value)) + return lab_name + + def EntryExitGlue3(self): + """ + 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})))) + # Reserve stack space for locals: + self.instructions.insert(2, makeIns(arm.subspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize)))) + # Setup frame pointer: + self.instructions.insert(3, makeIns(arm.movregreg_ext_ins(arm.r7, arm.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})))) + # 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]) diff -r bd2593de3ff8 -r 7b38782ed496 python/target/armtarget.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/armtarget.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,759 @@ +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 + + +""" ARM target description. """ + +# TODO: encode this in DSL (domain specific language) +# TBD: is this required? + +def u16(h): + return struct.pack(' 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 + + +@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 + + +@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('> 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() + diff -r bd2593de3ff8 -r 7b38782ed496 python/target/basetarget.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/basetarget.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,198 @@ +from asmnodes import ASymbol, AInstruction, ANumber +from ppci import CompilerError + +""" + Base classes for defining a target +""" + +# Machine code interface: +class Operand: + """ Single machine operand """ + pass + +# standard immediates: + +class Imm8: + def __init__(self, imm): + assert imm < 256 + 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 + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < 128: + return cls(vop.number) + +class Imm3: + def __init__(self, imm): + assert imm < 8 + assert type(imm) is int + self.imm = imm + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < 8: + return cls(vop.number) + +class Imm32: + def __init__(self, imm): + assert imm < 2**32 + assert type(imm) is int + self.imm = imm + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < 2**32: + return cls(vop.number) + + +class LabelRef: + def __init__(self, name): + assert type(name) is str + self.name = name + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + return cls(vop.name) + +class Instruction: + def encode(self): + raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self))) + def resolve(self, f): + pass + + +class Nop(Instruction): + """ Instruction that does nothing and has zero size """ + def encode(self): + return bytes() + + + +class PseudoInstruction(Instruction): + pass + + +class Label(PseudoInstruction): + def __init__(self, name): + self.name = name + self.address = 0 + + def __repr__(self): + return '{}:'.format(self.name) + + def encode(self): + return bytes() + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + name = vop.name + return cls(name) + + +class Comment(PseudoInstruction): + def __init__(self, txt): + self.txt = txt + + def encode(self): + return bytes() + + def __repr__(self): + return '; {}'.format(self.txt) + + +class Alignment(PseudoInstruction): + def __init__(self, a): + self.align = a + + def __repr__(self): + return 'ALIGN({})'.format(self.align) + + def encode(self): + pad = [] + address = self.address + while (address % self.align) != 0: + address += 1 + pad.append(0) + return bytes(pad) + +class DebugInfo(PseudoInstruction): + def __init__(self, i): + self.info = i + + def __repr__(self): + return 'DebugInfo: {}'.format(self.info) + + def encode(self): + return bytes() + +class Register(Operand): + def __init__(self, name): + self.name = name + + +class Target: + def __init__(self, name, desc=''): + self.name = name + self.desc = desc + self.registers = [] + self.instructions = [] + + def instruction(self, cls): + """ Decorator function that registers an instruction to this target """ + self.addInstruction(cls) + return cls + + def check(self): + """ Check target """ + for i in self.instructions: + assert hasattr(i, 'mnemonic') + assert hasattr(i, 'operands'), str(i) + assert type(i.mnemonic) is str + assert type(i.operands) is tuple, str(i) + + def addInstruction(self, ins_class): + self.instructions.append(ins_class) + + def mapOperand(self, operand): + """ Try to map an operand to a target type """ + if type(operand) is ASymbol: + # Try to map to register: + regs = {} + for r in self.registers: + regs[r.name] = r + if operand.name in regs: + return regs[operand.name] + raise CompilerError('Cannot map {0}'.format(operand)) + + def mapInstruction(self, vi): + assert type(vi) is AInstruction + """ Map ast tree to real instruction for this target """ + + # map to real operands: + if vi.mnemonic.upper() == 'ALIGN' and len(vi.operands) == 1: + if type(vi.operands[0]) == ANumber: + return Alignment(vi.operands[0].number) + + # look for a suitable instruction + for ic in self.instructions: + if ic.mnemonic.upper() == vi.mnemonic.upper() and len(ic.operands) == len(vi.operands): + # Try to map operands to the correct operand types: + rops = [roptype.Create(vop) for roptype, vop in zip(ic.operands, vi.operands)] + + # Check if we succeeded: + 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)) + diff -r bd2593de3ff8 -r 7b38782ed496 python/target/instructionselector.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/instructionselector.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,59 @@ +import ir +import irmach +from irmach import AbstractInstruction as makeIns +import target + +def genTemps(): + n = 900 + while True: + yield ir.Temp('t{}'.format(n)) + n = n + 1 + + +class InstructionSelector: + """ + Base instruction selector. This class must be overridden by + backends. + """ + def __init__(self): + self.temps = genTemps() + + def newTmp(self): + return self.temps.__next__() + + def munchFunction(self, f, frame): + # Entry point for instruction selection + assert isinstance(f, ir.Function) + self.targets = {} + # Enter a frame per function: + self.frame = frame + # First define labels: + for bb in f.Blocks: + itgt = makeIns(target.Label(bb.name)) + self.targets[bb] = itgt + # Generate code for all blocks: + for bb in f.Blocks: + self.emit2(self.targets[bb]) + for i in bb.Instructions: + self.munchStm(i) + self.munchStm(ir.Move(self.frame.rv, f.return_value)) + + def move(self, dst, src): + raise NotImplementedError('Not target implemented') + + def emit(self, *args, **kwargs): + """ Abstract instruction emitter """ + i = makeIns(*args, **kwargs) + return self.emit2(i) + + def emit2(self, i): + self.frame.instructions.append(i) + return i + + def munchStm(self, s): + """ Implement this in the target specific back-end """ + raise NotImplementedError() + + def munchExpr(self, e): + """ Implement this in the target specific back-end """ + raise NotImplementedError() diff -r bd2593de3ff8 -r 7b38782ed496 python/target/msp430.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/msp430.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,248 @@ +from target import Register, Instruction, Target +from asmnodes import ASymbol, ANumber +from ppci import CompilerError +import struct +import types + +# Create the target class (singleton): +msp430target = Target("MSP430") + +REGISTER_MODE = 1 +SYMBOLIC_MODE = 3 +ABSOLUTE_MODE = 4 +#TODO: add more modes! +IMMEDIATE_MODE = 7 + +# Target description for the MSP430 processor + +class MSP430Reg(Register): + def __init__(self, num, name): + super().__init__(name) + self.num = num + +# 8 bit registers: +PCB = MSP430Reg(0, 'r0') +rpc = PCB +r11 = MSP430Reg(11, 'r11') +r12 = MSP430Reg(12, 'r12') +r13 = MSP430Reg(13, 'r13') +r14 = MSP430Reg(14, 'r14') +r15 = MSP430Reg(15, 'r15') + +class MSP430Mem: + pass + +msp430target.registers.append(r11) +msp430target.registers.append(r12) +msp430target.registers.append(r13) +msp430target.registers.append(r14) +msp430target.registers.append(r15) + +# .. etc + +#GR8 = RegisterClass((PCB, R15B)) + +class MSP430Operand: + def __init__(self, mode, param): + self.mode = mode + self.param = param + def regField(self): + if self.mode == REGISTER_MODE: + return self.param + elif self.mode == IMMEDIATE_MODE: + return rpc.num + def asField(self): + if self.mode == REGISTER_MODE: + return 0 + elif self.mode == IMMEDIATE_MODE: + return 3 + def adField(self): + if self.mode == REGISTER_MODE: + return 0 + elif self.mode == IMMEDIATE_MODE: + raise CompilerError('Cannot use immediate mode for destination operand') + def extraBytes(self): + if self.mode == IMMEDIATE_MODE: + return pack_ins(self.param) + return bytes() + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + # try to map to register: + regs = {} + for r in msp430target.registers: + regs[r.name] = r + if vop.name in regs: + reg = regs[vop.name] + return cls(REGISTER_MODE, reg.num) + elif type(vop) is ANumber: + # Immediate mode: + return cls(IMMEDIATE_MODE, vop.number) + +def pack_ins(h): + return struct.pack('':'jg', '<':'jl', '==':'je'} + if i.cond in jmps: + j = jmps[i.cond] + self.emit('{0} {1}'.format(j, i.lab1.name)) + else: + raise NotImplementedError('condition {0}'.format(i.cond)) + self.emit('jmp {0}'.format(i.lab2.name)) + elif type(i) is ir.Branch: + self.emit('jmp {0}'.format(i.target.name)) + elif type(i) is ir.Alloc: + pass + else: + raise NotImplementedError('{0}'.format(i)) + diff -r bd2593de3ff8 -r 7b38782ed496 python/target/x86_2.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target/x86_2.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,356 @@ +""" + X86 target descriptions and encodings. + +""" + +from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef + + +modrm = {'rax': 0, 'rbx': 1} + +# Table 3.1 of the intel manual: +# use REX.W on the table below: +regs64 = {'rax': 0,'rcx':1,'rdx':2,'rbx':3,'rsp':4,'rbp':5,'rsi':6,'rdi':7,'r8':0,'r9':1,'r10':2,'r11':3,'r12':4,'r13':5,'r14':6,'r15':7} +regs32 = {'eax': 0, 'ecx':1, 'edx':2, 'ebx': 3, 'esp': 4, 'ebp': 5, 'esi':6, 'edi':7} +regs8 = {'al':0,'cl':1,'dl':2,'bl':3,'ah':4,'ch':5,'dh':6,'bh':7} + +# Calculation of the rexb bit: +rexbit = {'rax': 0, 'rcx':0, 'rdx':0, 'rbx': 0, 'rsp': 0, 'rbp': 0, 'rsi':0, 'rdi':0,'r8':1,'r9':1,'r10':1,'r11':1,'r12':1,'r13':1,'r14':1,'r15':1} + +# Helper functions: +def imm64(x): + """ represent 64 bits integer in little endian 8 bytes""" + if x < 0: + x = x + (1 << 64) + x = x & 0xFFFFFFFFFFFFFFFF + return [ (x >> (p*8)) & 0xFF for p in range(8) ] + +def imm32(x): + """ represent 32 bits integer in little endian 4 bytes""" + if x < 0: + x = x + (1 << 32) + x = x & 0xFFFFFFFF + return [ (x >> (p*8)) & 0xFF for p in range(4) ] + +def imm8(x): + if x < 0: + x = x + (1 << 8) + x = x & 0xFF + return [ x ] + +def modrm(mod=0, rm=0, reg=0): + """ Construct the modrm byte from its components """ + assert(mod <= 3) + assert(rm <= 7) + assert(reg <= 7) + return (mod << 6) | (reg << 3) | rm + +def rex(w=0, r=0, x=0, b=0): + """ Create a REX prefix byte """ + assert(w <= 1) + assert(r <= 1) + assert(x <= 1) + assert(b <= 1) + return 0x40 | (w<<3) | (r<<2) | (x<<1) | b + +def sib(ss=0, index=0, base=0): + assert(ss <= 3) + assert(index <= 7) + assert(base <= 7) + return (ss << 6) | (index << 3) | base + +tttn = {'L':0xc,'G':0xf,'NE':0x5,'GE':0xd,'LE':0xe, 'E':0x4} + +# Actual instructions: +def nearjump(distance, condition=None): + """ jmp imm32 """ + lim = (1<<30) + if abs(distance) > lim: + Error('near jump cannot jump over more than {0} bytes'.format(lim)) + if condition: + if distance < 0: + distance -= 6 # Skip own instruction + opcode = 0x80 | tttn[condition] # Jcc imm32 + return [0x0F, opcode] + imm32(distance) + else: + if distance < 0: + distance -= 5 # Skip own instruction + return [ 0xE9 ] + imm32(distance) + +def shortjump(distance, condition=None): + """ jmp imm8 """ + lim = 118 + if abs(distance) > lim: + Error('short jump cannot jump over more than {0} bytes'.format(lim)) + if distance < 0: + distance -= 2 # Skip own instruction + if condition: + opcode = 0x70 | tttn[condition] # Jcc rel8 + else: + opcode = 0xeb # jmp rel8 + return [opcode] + imm8(distance) + +# Helper that determines jump type: +def reljump(distance): + if abs(distance) < 110: + return shortjump(distance) + else: + return nearjump(distance) + +def push(reg): + if reg in regs64: + if rexbit[reg] == 1: + return [0x41, 0x50 + regs64[reg]] + else: + return [0x50 + regs64[reg]] + else: + Error('push for {0} not implemented'.format(reg)) + +def pop(reg): + if reg in regs64: + if rexbit[reg] == 1: + rexprefix = rex(b=1) + opcode = 0x58 + regs64[reg] + return [rexprefix, opcode] + else: + opcode = 0x58 + regs64[reg] + return [ opcode ] + else: + Error('pop for {0} not implemented'.format(reg)) + +def INT(number): + opcode = 0xcd + return [opcode] + imm8(number) + +def syscall(): + return [0x0F, 0x05] + +def call(distance): + if type(distance) is int: + return [0xe8]+imm32(distance) + elif type(distance) is str and distance in regs64: + reg = distance + opcode = 0xFF # 0xFF /2 == call r/m64 + mod_rm = modrm(mod=3, reg=2, rm=regs64[reg]) + if rexbit[reg] == 1: + rexprefix = rex(b=rexbit[reg]) + return [rexprefix, opcode, mod_rm] + else: + return [opcode, mod_rm] + else: + Error('Cannot call to {0}'.format(distance)) + +def ret(): + return [ 0xc3 ] + +def increg64(reg): + assert(reg in regs64) + rexprefix = rex(w=1, b=rexbit[reg]) + opcode = 0xff + mod_rm = modrm(mod=3, rm=regs64[reg]) + return [rexprefix, opcode, mod_rm] + +def prepost8(r8, rm8): + assert(r8 in regs8) + pre = [] + if type(rm8) is list: + # TODO: merge mem access with prepost for 64 bits + if len(rm8) == 1: + base, = rm8 + if type(base) is str and base in regs64: + assert(not base in ['rbp', 'rsp', 'r12', 'r13']) + mod_rm = modrm(mod=0, rm=regs64[base], reg=regs8[r8]) + if rexbit[base] == 1: + pre.append(rex(b=1)) + post = [mod_rm] + else: + Error('One arg of type {0} not implemented'.format(base)) + elif len(rm8) == 2: + base, offset = rm8 + assert(type(offset) is int) + assert(base in regs64) + + if base == 'rsp' or base == 'r12': + Error('Cannot use rsp or r12 as base yet') + if rexbit[base] == 1: + pre.append( rex(b=1) ) + mod_rm = modrm(mod=1, rm=regs64[base], reg=regs8[r8]) + post = [mod_rm] + imm8(offset) + else: + Error('not supporting prepost8 with list len {0}'.format(len(rm8))) + else: + Error('Not supporting move with reg8 {0}'.format(r8)) + return pre, post + +def prepost(r64, rm64): + assert(r64 in regs64) + if type(rm64) is list: + if len(rm64) == 3: + base, index, disp = rm64 + assert(base in regs64) + assert(index in regs64) + assert(type(disp) is int) + # Assert that no special cases are used: + # TODO: swap base and index to avoid special cases + # TODO: exploit special cases and make better code + assert(index != 'rsp') + + rexprefix = rex(w=1, r=rexbit[r64], x=rexbit[index], b=rexbit[base]) + # mod=1 and rm=4 indicates a SIB byte: [--][--]+imm8 + mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) + si_b = sib(ss=0, index=regs64[index], base=regs64[base]) + return [rexprefix], [mod_rm, si_b] + imm8(disp) + elif len(rm64) == 2: + base, offset = rm64 + assert(type(offset) is int) + if base == 'RIP': + # RIP pointer relative addressing mode! + rexprefix = rex(w=1, r=rexbit[r64]) + mod_rm = modrm(mod=0, rm=5, reg=regs64[r64]) + return [rexprefix], [mod_rm] + imm32(offset) + else: + assert(base in regs64) + + if base == 'rsp' or base == 'r12': + # extended function that uses SIB byte + rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) + # rm=4 indicates a SIB byte follows + mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) + # index=4 indicates that index is not used + si_b = sib(ss=0, index=4, base=regs64[base]) + return [rexprefix], [mod_rm, si_b] + imm8(offset) + else: + rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) + mod_rm = modrm(mod=1, rm=regs64[base], reg=regs64[r64]) + return [rexprefix], [mod_rm] + imm8(offset) + elif len(rm64) == 1: + offset = rm64[0] + if type(offset) is int: + rexprefix = rex(w=1, r=rexbit[r64]) + mod_rm = modrm(mod=0, rm=4,reg=regs64[r64]) + si_b = sib(ss=0, index=4,base=5) # 0x25 + return [rexprefix], [mod_rm, si_b] + imm32(offset) + else: + Error('Memory reference of type {0} not implemented'.format(offset)) + else: + Error('Memory reference not implemented') + elif rm64 in regs64: + rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[rm64]) + mod_rm = modrm(3, rm=regs64[rm64], reg=regs64[r64]) + return [rexprefix], [mod_rm] + +def leareg64(rega, m): + opcode = 0x8d # lea r64, m + pre, post = prepost(rega, m) + return pre + [opcode] + post + +def mov(rega, regb): + if type(regb) is int: + pre = [rex(w=1, b=rexbit[rega])] + opcode = 0xb8 + regs64[rega] + post = imm64(regb) + elif type(regb) is str: + if regb in regs64: + opcode = 0x89 # mov r/m64, r64 + pre, post = prepost(regb, rega) + elif regb in regs8: + opcode = 0x88 # mov r/m8, r8 + pre, post = prepost8(regb, rega) + else: + Error('Unknown register {0}'.format(regb)) + elif type(rega) is str: + if rega in regs64: + opcode = 0x8b # mov r64, r/m64 + pre, post = prepost(rega, regb) + else: + Error('Unknown register {0}'.format(rega)) + else: + Error('Move of this kind {0}, {1} not implemented'.format(rega, regb)) + return pre + [opcode] + post + +def xorreg64(rega, regb): + rexprefix = rex(w=1, r=rexbit[regb], b=rexbit[rega]) + opcode = 0x31 # XOR r/m64, r64 + # Alternative is 0x33 XOR r64, r/m64 + mod_rm = modrm(3, rm=regs64[rega], reg=regs64[regb]) + return [rexprefix, opcode, mod_rm] + +# integer arithmatic: +def addreg64(rega, regb): + if regb in regs64: + pre, post = prepost(regb, rega) + opcode = 0x01 # ADD r/m64, r64 + return pre + [opcode] + post + elif type(regb) is int: + if regb < 100: + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x83 # add r/m, imm8 + mod_rm = modrm(3, rm=regs64[rega], reg=0) + return [rexprefix, opcode, mod_rm]+imm8(regb) + elif regb < (1<<31): + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x81 # add r/m64, imm32 + mod_rm = modrm(3, rm=regs64[rega], reg=0) + return [rexprefix, opcode, mod_rm]+imm32(regb) + else: + Error('Constant value too large!') + else: + Error('unknown second operand!'.format(regb)) + +def subreg64(rega, regb): + if regb in regs64: + pre, post = prepost(regb, rega) + opcode = 0x29 # SUB r/m64, r64 + return pre + [opcode] + post + elif type(regb) is int: + if regb < 100: + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x83 # sub r/m, imm8 + mod_rm = modrm(3, rm=regs64[rega], reg=5) + return [rexprefix, opcode, mod_rm]+imm8(regb) + elif regb < (1<<31): + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x81 # sub r/m64, imm32 + mod_rm = modrm(3, rm=regs64[rega], reg=5) + return [rexprefix, opcode, mod_rm]+imm32(regb) + else: + Error('Constant value too large!') + + else: + Error('unknown second operand!'.format(regb)) + +def idivreg64(reg): + rexprefix = rex(w=1, b=rexbit[reg]) + opcode = 0xf7 # IDIV r/m64 + mod_rm = modrm(3, rm=regs64[reg], reg=7) + return [rexprefix, opcode, mod_rm] + +def imulreg64_rax(reg): + rexprefix = rex(w=1, b=rexbit[reg]) + opcode = 0xf7 # IMUL r/m64 + mod_rm = modrm(3, rm=regs64[reg], reg=5) + return [rexprefix, opcode, mod_rm] + +def imulreg64(rega, regb): + pre, post = prepost(rega, regb) + opcode = 0x0f # IMUL r64, r/m64 + opcode2 = 0xaf + return pre + [opcode, opcode2] + post + +def cmpreg64(rega, regb): + if regb in regs64: + pre, post = prepost(regb, rega) + opcode = 0x39 # CMP r/m64, r64 + return pre + [opcode] + post + elif type(regb) is int: + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x83 # CMP r/m64, imm8 + mod_rm = modrm(3, rm=regs64[rega], reg=7) + return [rexprefix, opcode, mod_rm] + imm8(regb) + + else: + Error('not implemented cmp64') + +# Mapping that maps string names to the right functions: +opcodes = {'mov':(mov,2), 'lea':(leareg64,2), 'int':(INT,1), 'syscall':(syscall,0)} + diff -r bd2593de3ff8 -r 7b38782ed496 python/tcodegen.py --- a/python/tcodegen.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ - -""" - Test individual parts of the code generation for arm using the c3 frontend. -""" - -import c3 -import ppci -import codegenarm -import outstream -import ir - -testsrc = """ -package test2; - -var int phaa, foo, bar; - -function int insanemath(int a, int b) -{ - var int c; - c = 0; - var int i; - i = 9; - while (i > 1) - { - c = a + b + 1 + c; - i = i - 1; - if (c > 90) - { - return 42; - } - } - return c; -} - -function void tesssst(int henkie) -{ - var int a, b, cee; - a = 2 * 33 - 12; - b = a * 2; - a = b + a; - cee = a; - cee = cee * 2 + cee; - insanemath(2, 3); - if (cee + a > b and b - a+b== 3*6-insanemath(b, 2)) - { - var int x = a; - x = b - a + insanemath(3, 4) - insanemath(33, insanemath(2, 0)); - a = x * (x + a); - } - else - { - a = b + (a + b); - } - var int y; - y = a - b * 53; -} -""" - -testsrc = """ -package test3; - -function int ab(int a, int b) -{ - var int c; - c = 0; - c = c + a + b; - return c; -} - -function void tesssst() -{ - var int a, b; - a = 2; - b = 3; - ab(ab(a, b) + ab(9,b), 0); -} -""" - -testsrc = """ -package test3; - -function int ab(int a, int b) -{ - var int c; - var int *a2; - a2 = cast(2); - *a2 = 2; - *a2 = *a2 + 2; - c = 0; - c = c + a + b; - return c; -} - -""" -def dump_cfg(cga, cfg_file): - print('digraph G {', file=cfg_file) - #print('edge [constraint=none]', file=cfg_file) - print('rankdir=TB', file=cfg_file) - for f in cga.frames: - print('subgraph cluster_{} {{'.format(f.name), file=cfg_file) - print('label={};'.format(f.name), file=cfg_file) - print('color=lightgrey;', file=cfg_file) - print('style=filled;', file=cfg_file) - f.cfg.to_dot(cfg_file) - print('}', file=cfg_file) - print('}', file=cfg_file) - -def dump_ig(cga, ig_file): - print('digraph G {', file=ig_file) - print('edge [arrowhead=none]', file=ig_file) - for f in cga.frames: - print('subgraph cluster_{} {{'.format(f.name), file=ig_file) - print('label={};'.format(f.name), file=ig_file) - print('color=lightgrey;', file=ig_file) - print('style=filled;', file=ig_file) - f.ig.to_dot(ig_file) - print('}', file=ig_file) - print('}', file=ig_file) - -if __name__ == '__main__': - diag = ppci.DiagnosticsManager() - builder = c3.Builder(diag) - irc = builder.build(testsrc) - if not irc: - diag.printErrors(testsrc) - irc.check() - #irc.dump() - with open('ir.gv', 'w') as f: - ir.dumpgv(irc, f) - outs = outstream.TextOutputStream() - cga = codegenarm.ArmCodeGenerator(outs) - ir2 = cga.generate(irc) - - with open('cfg.gv', 'w') as cfg_file: - dump_cfg(cga, cfg_file) - - with open('ig.gv', 'w') as ig_file: - dump_ig(cga, ig_file) - - outs.dump() - diff -r bd2593de3ff8 -r 7b38782ed496 python/utils/iso9660.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/iso9660.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +import argparse + +__doc__ = """ + ISO 9660 filesystem utility. +""" + + +class VolumeDescriptor: + @classmethod + def FromData(cls, d): + ty = d[0] + Id = d[1:6] + assert Id == 'CD001'.encode('ascii') + ver = d[6] + assert ver == 1 + cls = vol_desc_types[ty] + return cls(d) + + +vol_desc_types = {} +def vol_type(t): + def reg_func(cls): + vol_desc_types[t] = cls + return cls + return reg_func + + +@vol_type(0) +class BootRecordVolumeDescriptor(VolumeDescriptor): + def __init__(self, d): + boot_sys_id = d[7:39] + boot_id = d[39:71] + print(boot_sys_id) + print(boot_id) + + +@vol_type(1) +class PrimaryVolumeDescriptor(VolumeDescriptor): + def __init__(self, d): + sys_id = d[8:40] + vol_id = d[40:72] + print(sys_id) + print(vol_id) + + +@vol_type(255) +class VolumeDescriptorTerminator(VolumeDescriptor): + def __init__(self, d): + pass + + +class ISOfs: + def __init__(self): + self.vol_descriptors = [] + + def read(self, f): + # System area: + self.system_area = f.read(16 * 2048) + while True: + d = f.read(2048) + desc = VolumeDescriptor.FromData(d) + self.vol_descriptors.append(desc) + if type(desc) is VolumeDescriptorTerminator: + break + + def dump(self): + for vd in self.vol_descriptors: + print(vd) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('filename') + args = parser.parse_args() + fs = ISOfs() + with open(args.filename, 'rb') as f: + fs.read(f) + fs.dump() + + diff -r bd2593de3ff8 -r 7b38782ed496 python/x86.py --- a/python/x86.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -import ppci -import ir - -class X86CodeGenSimple: - """ - Inefficient code generation, assume stack machine - backend - """ - def __init__(self, diag): - self.diag = diag - - def emit(self, i): - self.asm.append(i) - - def genBin(self, ir): - self.asm = [] - self.genModule(ir) - return self.asm - - def genModule(self, ir): - for f in ir.Functions: - self.genFunction(f) - def genFunction(self, f): - self.emit('global {0}'.format(f.name)) - self.emit('{0}:'.format(f.name)) - self.emit('jmp {0}'.format(f.entry.name)) - for bb in f.BasicBlocks: - self.genBB(bb) - def genBB(self, bb): - self.emit('{0}:'.format(bb.name)) - for i in bb.Instructions: - self.genIns(i) - def genIns(self, i): - if type(i) is ir.BinaryOperator: - ops = {'+':'add', '-':'sub', '*':'mul'} - if i.operation in ops: - i.result.reg = 'rax' - i.value1.reg = 'rbx' - i.value2.reg = 'rbx' - self.emit('mov {0}, {1}'.format(i.result.reg, i.value1.reg)) - self.emit('{0} {1}, {2}'.format(ops[i.operation], i.result.reg, i.value2.reg)) - else: - raise NotImplementedError('op {0}'.format(i.operation)) - elif type(i) is ir.Load: - self.emit('mov {0}, [{1}]'.format(i.value, i.location)) - elif type(i) is ir.Return: - self.emit('ret') - elif type(i) is ir.Call: - self.emit('call') - elif type(i) is ir.ImmLoad: - self.emit('mov {0}, {1}'.format(i.target, i.value)) - elif type(i) is ir.Store: - self.emit('mov [{0}], {1}'.format(i.location, i.value)) - elif type(i) is ir.ConditionalBranch: - self.emit('cmp {0}, {1}'.format(i.a, i.b)) - jmps = {'>':'jg', '<':'jl', '==':'je'} - if i.cond in jmps: - j = jmps[i.cond] - self.emit('{0} {1}'.format(j, i.lab1.name)) - else: - raise NotImplementedError('condition {0}'.format(i.cond)) - self.emit('jmp {0}'.format(i.lab2.name)) - elif type(i) is ir.Branch: - self.emit('jmp {0}'.format(i.target.name)) - elif type(i) is ir.Alloc: - pass - else: - raise NotImplementedError('{0}'.format(i)) - diff -r bd2593de3ff8 -r 7b38782ed496 python/x86_2.py --- a/python/x86_2.py Thu Nov 21 15:46:50 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -""" - X86 target descriptions and encodings. - -""" - -from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef - - -modrm = {'rax': 0, 'rbx': 1} - -# Table 3.1 of the intel manual: -# use REX.W on the table below: -regs64 = {'rax': 0,'rcx':1,'rdx':2,'rbx':3,'rsp':4,'rbp':5,'rsi':6,'rdi':7,'r8':0,'r9':1,'r10':2,'r11':3,'r12':4,'r13':5,'r14':6,'r15':7} -regs32 = {'eax': 0, 'ecx':1, 'edx':2, 'ebx': 3, 'esp': 4, 'ebp': 5, 'esi':6, 'edi':7} -regs8 = {'al':0,'cl':1,'dl':2,'bl':3,'ah':4,'ch':5,'dh':6,'bh':7} - -# Calculation of the rexb bit: -rexbit = {'rax': 0, 'rcx':0, 'rdx':0, 'rbx': 0, 'rsp': 0, 'rbp': 0, 'rsi':0, 'rdi':0,'r8':1,'r9':1,'r10':1,'r11':1,'r12':1,'r13':1,'r14':1,'r15':1} - -# Helper functions: -def imm64(x): - """ represent 64 bits integer in little endian 8 bytes""" - if x < 0: - x = x + (1 << 64) - x = x & 0xFFFFFFFFFFFFFFFF - return [ (x >> (p*8)) & 0xFF for p in range(8) ] - -def imm32(x): - """ represent 32 bits integer in little endian 4 bytes""" - if x < 0: - x = x + (1 << 32) - x = x & 0xFFFFFFFF - return [ (x >> (p*8)) & 0xFF for p in range(4) ] - -def imm8(x): - if x < 0: - x = x + (1 << 8) - x = x & 0xFF - return [ x ] - -def modrm(mod=0, rm=0, reg=0): - """ Construct the modrm byte from its components """ - assert(mod <= 3) - assert(rm <= 7) - assert(reg <= 7) - return (mod << 6) | (reg << 3) | rm - -def rex(w=0, r=0, x=0, b=0): - """ Create a REX prefix byte """ - assert(w <= 1) - assert(r <= 1) - assert(x <= 1) - assert(b <= 1) - return 0x40 | (w<<3) | (r<<2) | (x<<1) | b - -def sib(ss=0, index=0, base=0): - assert(ss <= 3) - assert(index <= 7) - assert(base <= 7) - return (ss << 6) | (index << 3) | base - -tttn = {'L':0xc,'G':0xf,'NE':0x5,'GE':0xd,'LE':0xe, 'E':0x4} - -# Actual instructions: -def nearjump(distance, condition=None): - """ jmp imm32 """ - lim = (1<<30) - if abs(distance) > lim: - Error('near jump cannot jump over more than {0} bytes'.format(lim)) - if condition: - if distance < 0: - distance -= 6 # Skip own instruction - opcode = 0x80 | tttn[condition] # Jcc imm32 - return [0x0F, opcode] + imm32(distance) - else: - if distance < 0: - distance -= 5 # Skip own instruction - return [ 0xE9 ] + imm32(distance) - -def shortjump(distance, condition=None): - """ jmp imm8 """ - lim = 118 - if abs(distance) > lim: - Error('short jump cannot jump over more than {0} bytes'.format(lim)) - if distance < 0: - distance -= 2 # Skip own instruction - if condition: - opcode = 0x70 | tttn[condition] # Jcc rel8 - else: - opcode = 0xeb # jmp rel8 - return [opcode] + imm8(distance) - -# Helper that determines jump type: -def reljump(distance): - if abs(distance) < 110: - return shortjump(distance) - else: - return nearjump(distance) - -def push(reg): - if reg in regs64: - if rexbit[reg] == 1: - return [0x41, 0x50 + regs64[reg]] - else: - return [0x50 + regs64[reg]] - else: - Error('push for {0} not implemented'.format(reg)) - -def pop(reg): - if reg in regs64: - if rexbit[reg] == 1: - rexprefix = rex(b=1) - opcode = 0x58 + regs64[reg] - return [rexprefix, opcode] - else: - opcode = 0x58 + regs64[reg] - return [ opcode ] - else: - Error('pop for {0} not implemented'.format(reg)) - -def INT(number): - opcode = 0xcd - return [opcode] + imm8(number) - -def syscall(): - return [0x0F, 0x05] - -def call(distance): - if type(distance) is int: - return [0xe8]+imm32(distance) - elif type(distance) is str and distance in regs64: - reg = distance - opcode = 0xFF # 0xFF /2 == call r/m64 - mod_rm = modrm(mod=3, reg=2, rm=regs64[reg]) - if rexbit[reg] == 1: - rexprefix = rex(b=rexbit[reg]) - return [rexprefix, opcode, mod_rm] - else: - return [opcode, mod_rm] - else: - Error('Cannot call to {0}'.format(distance)) - -def ret(): - return [ 0xc3 ] - -def increg64(reg): - assert(reg in regs64) - rexprefix = rex(w=1, b=rexbit[reg]) - opcode = 0xff - mod_rm = modrm(mod=3, rm=regs64[reg]) - return [rexprefix, opcode, mod_rm] - -def prepost8(r8, rm8): - assert(r8 in regs8) - pre = [] - if type(rm8) is list: - # TODO: merge mem access with prepost for 64 bits - if len(rm8) == 1: - base, = rm8 - if type(base) is str and base in regs64: - assert(not base in ['rbp', 'rsp', 'r12', 'r13']) - mod_rm = modrm(mod=0, rm=regs64[base], reg=regs8[r8]) - if rexbit[base] == 1: - pre.append(rex(b=1)) - post = [mod_rm] - else: - Error('One arg of type {0} not implemented'.format(base)) - elif len(rm8) == 2: - base, offset = rm8 - assert(type(offset) is int) - assert(base in regs64) - - if base == 'rsp' or base == 'r12': - Error('Cannot use rsp or r12 as base yet') - if rexbit[base] == 1: - pre.append( rex(b=1) ) - mod_rm = modrm(mod=1, rm=regs64[base], reg=regs8[r8]) - post = [mod_rm] + imm8(offset) - else: - Error('not supporting prepost8 with list len {0}'.format(len(rm8))) - else: - Error('Not supporting move with reg8 {0}'.format(r8)) - return pre, post - -def prepost(r64, rm64): - assert(r64 in regs64) - if type(rm64) is list: - if len(rm64) == 3: - base, index, disp = rm64 - assert(base in regs64) - assert(index in regs64) - assert(type(disp) is int) - # Assert that no special cases are used: - # TODO: swap base and index to avoid special cases - # TODO: exploit special cases and make better code - assert(index != 'rsp') - - rexprefix = rex(w=1, r=rexbit[r64], x=rexbit[index], b=rexbit[base]) - # mod=1 and rm=4 indicates a SIB byte: [--][--]+imm8 - mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) - si_b = sib(ss=0, index=regs64[index], base=regs64[base]) - return [rexprefix], [mod_rm, si_b] + imm8(disp) - elif len(rm64) == 2: - base, offset = rm64 - assert(type(offset) is int) - if base == 'RIP': - # RIP pointer relative addressing mode! - rexprefix = rex(w=1, r=rexbit[r64]) - mod_rm = modrm(mod=0, rm=5, reg=regs64[r64]) - return [rexprefix], [mod_rm] + imm32(offset) - else: - assert(base in regs64) - - if base == 'rsp' or base == 'r12': - # extended function that uses SIB byte - rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) - # rm=4 indicates a SIB byte follows - mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) - # index=4 indicates that index is not used - si_b = sib(ss=0, index=4, base=regs64[base]) - return [rexprefix], [mod_rm, si_b] + imm8(offset) - else: - rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) - mod_rm = modrm(mod=1, rm=regs64[base], reg=regs64[r64]) - return [rexprefix], [mod_rm] + imm8(offset) - elif len(rm64) == 1: - offset = rm64[0] - if type(offset) is int: - rexprefix = rex(w=1, r=rexbit[r64]) - mod_rm = modrm(mod=0, rm=4,reg=regs64[r64]) - si_b = sib(ss=0, index=4,base=5) # 0x25 - return [rexprefix], [mod_rm, si_b] + imm32(offset) - else: - Error('Memory reference of type {0} not implemented'.format(offset)) - else: - Error('Memory reference not implemented') - elif rm64 in regs64: - rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[rm64]) - mod_rm = modrm(3, rm=regs64[rm64], reg=regs64[r64]) - return [rexprefix], [mod_rm] - -def leareg64(rega, m): - opcode = 0x8d # lea r64, m - pre, post = prepost(rega, m) - return pre + [opcode] + post - -def mov(rega, regb): - if type(regb) is int: - pre = [rex(w=1, b=rexbit[rega])] - opcode = 0xb8 + regs64[rega] - post = imm64(regb) - elif type(regb) is str: - if regb in regs64: - opcode = 0x89 # mov r/m64, r64 - pre, post = prepost(regb, rega) - elif regb in regs8: - opcode = 0x88 # mov r/m8, r8 - pre, post = prepost8(regb, rega) - else: - Error('Unknown register {0}'.format(regb)) - elif type(rega) is str: - if rega in regs64: - opcode = 0x8b # mov r64, r/m64 - pre, post = prepost(rega, regb) - else: - Error('Unknown register {0}'.format(rega)) - else: - Error('Move of this kind {0}, {1} not implemented'.format(rega, regb)) - return pre + [opcode] + post - -def xorreg64(rega, regb): - rexprefix = rex(w=1, r=rexbit[regb], b=rexbit[rega]) - opcode = 0x31 # XOR r/m64, r64 - # Alternative is 0x33 XOR r64, r/m64 - mod_rm = modrm(3, rm=regs64[rega], reg=regs64[regb]) - return [rexprefix, opcode, mod_rm] - -# integer arithmatic: -def addreg64(rega, regb): - if regb in regs64: - pre, post = prepost(regb, rega) - opcode = 0x01 # ADD r/m64, r64 - return pre + [opcode] + post - elif type(regb) is int: - if regb < 100: - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x83 # add r/m, imm8 - mod_rm = modrm(3, rm=regs64[rega], reg=0) - return [rexprefix, opcode, mod_rm]+imm8(regb) - elif regb < (1<<31): - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x81 # add r/m64, imm32 - mod_rm = modrm(3, rm=regs64[rega], reg=0) - return [rexprefix, opcode, mod_rm]+imm32(regb) - else: - Error('Constant value too large!') - else: - Error('unknown second operand!'.format(regb)) - -def subreg64(rega, regb): - if regb in regs64: - pre, post = prepost(regb, rega) - opcode = 0x29 # SUB r/m64, r64 - return pre + [opcode] + post - elif type(regb) is int: - if regb < 100: - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x83 # sub r/m, imm8 - mod_rm = modrm(3, rm=regs64[rega], reg=5) - return [rexprefix, opcode, mod_rm]+imm8(regb) - elif regb < (1<<31): - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x81 # sub r/m64, imm32 - mod_rm = modrm(3, rm=regs64[rega], reg=5) - return [rexprefix, opcode, mod_rm]+imm32(regb) - else: - Error('Constant value too large!') - - else: - Error('unknown second operand!'.format(regb)) - -def idivreg64(reg): - rexprefix = rex(w=1, b=rexbit[reg]) - opcode = 0xf7 # IDIV r/m64 - mod_rm = modrm(3, rm=regs64[reg], reg=7) - return [rexprefix, opcode, mod_rm] - -def imulreg64_rax(reg): - rexprefix = rex(w=1, b=rexbit[reg]) - opcode = 0xf7 # IMUL r/m64 - mod_rm = modrm(3, rm=regs64[reg], reg=5) - return [rexprefix, opcode, mod_rm] - -def imulreg64(rega, regb): - pre, post = prepost(rega, regb) - opcode = 0x0f # IMUL r64, r/m64 - opcode2 = 0xaf - return pre + [opcode, opcode2] + post - -def cmpreg64(rega, regb): - if regb in regs64: - pre, post = prepost(regb, rega) - opcode = 0x39 # CMP r/m64, r64 - return pre + [opcode] + post - elif type(regb) is int: - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x83 # CMP r/m64, imm8 - mod_rm = modrm(3, rm=regs64[rega], reg=7) - return [rexprefix, opcode, mod_rm] + imm8(regb) - - else: - Error('not implemented cmp64') - -# Mapping that maps string names to the right functions: -opcodes = {'mov':(mov,2), 'lea':(leareg64,2), 'int':(INT,1), 'syscall':(syscall,0)} - diff -r bd2593de3ff8 -r 7b38782ed496 python/zcc.py --- a/python/zcc.py Thu Nov 21 15:46:50 2013 +0100 +++ b/python/zcc.py Sun Nov 24 11:24:15 2013 +0100 @@ -7,10 +7,9 @@ import c3 import ppci import codegen -import codegenarm -from optimize import optimize import outstream import hexfile +import target logformat='%(asctime)s|%(levelname)s|%(name)s|%(message)s' @@ -23,20 +22,25 @@ return numeric_level +target_list = [target.armtarget] +targetnames = {t.name: t for t in target_list} + # Parse arguments: parser = argparse.ArgumentParser(description='lcfos Compiler') # Input: parser.add_argument('source', type=argparse.FileType('r'), \ help='the source file to build', nargs="+") -parser.add_argument('-i', '--import', type=argparse.FileType('r'), \ +parser.add_argument('-i', '--imp', type=argparse.FileType('r'), \ help='Possible import module', action='append') parser.add_argument('--dumpir', action='store_true', help="Dump IR-code") 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") +parser.add_argument('--target', help="Backend selection", + choices=targetnames.keys()) parser.add_argument('-o', '--output', help='Output file', metavar='filename') -parser.add_argument('--hexfile', help='Output hexfile', type=argparse.FileType('w')) +parser.add_argument('--hexfile', help='Output hexfile', + type=argparse.FileType('w')) parser.add_argument('--log', help='Log level (INFO,DEBUG)', type=logLevel) @@ -48,26 +52,27 @@ logging.info('Zcc started') # Front end: c3b = c3.Builder(diag) + tg = target.armtarget.armtarget + # TODO select target here! + cg = codegen.CodeGenerator(outs, tg) for ircode in c3b.build(srcs, imps): if not ircode: return - # Optimization passes: - optimize(ircode) + # Optimization passes, TODO if dumpir: ircode.dump() - # TODO select target here! # Code generation: - codegenarm.ArmCodeGenerator(outs).generate(ircode) + cg.generate(ircode) return c3b.ok def main(args): logging.basicConfig(format=logformat, level=args.log) src = args.source - imps = getattr(args, 'import') + imps = args.imp diag = ppci.DiagnosticsManager() outs = outstream.TextOutputStream() diff -r bd2593de3ff8 -r 7b38782ed496 readme.rst --- a/readme.rst Thu Nov 21 15:46:50 2013 +0100 +++ b/readme.rst Sun Nov 24 11:24:15 2013 +0100 @@ -24,18 +24,23 @@ How to start the IDE -------------------- +.. code:: bash + cd python python ide.py Run unittests ------------- - cd python +.. code:: bash + + cd test python -m unittest + .. image:: https://drone.io/bitbucket.org/windel/lcfos/status.png -.. image:: https://codeship.io/projects/f4a4da90-2ffd-0131-58c6-5ea61a10d89b/status +.. image:: https://www.ohloh.net/p/lcfos/widgets/project_thin_badge.gif diff -r bd2593de3ff8 -r 7b38782ed496 test/tcodegen.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tcodegen.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,141 @@ + +""" + Test individual parts of the code generation for arm using the c3 frontend. +""" + +import c3 +import ppci +import codegenarm +import outstream +import ir + +testsrc = """ +package test2; + +var int phaa, foo, bar; + +function int insanemath(int a, int b) +{ + var int c; + c = 0; + var int i; + i = 9; + while (i > 1) + { + c = a + b + 1 + c; + i = i - 1; + if (c > 90) + { + return 42; + } + } + return c; +} + +function void tesssst(int henkie) +{ + var int a, b, cee; + a = 2 * 33 - 12; + b = a * 2; + a = b + a; + cee = a; + cee = cee * 2 + cee; + insanemath(2, 3); + if (cee + a > b and b - a+b== 3*6-insanemath(b, 2)) + { + var int x = a; + x = b - a + insanemath(3, 4) - insanemath(33, insanemath(2, 0)); + a = x * (x + a); + } + else + { + a = b + (a + b); + } + var int y; + y = a - b * 53; +} +""" + +testsrc = """ +package test3; + +function int ab(int a, int b) +{ + var int c; + c = 0; + c = c + a + b; + return c; +} + +function void tesssst() +{ + var int a, b; + a = 2; + b = 3; + ab(ab(a, b) + ab(9,b), 0); +} +""" + +testsrc = """ +package test3; + +function int ab(int a, int b) +{ + var int c; + var int *a2; + a2 = cast(2); + *a2 = 2; + *a2 = *a2 + 2; + c = 0; + c = c + a + b; + return c; +} + +""" +def dump_cfg(cga, cfg_file): + print('digraph G {', file=cfg_file) + #print('edge [constraint=none]', file=cfg_file) + print('rankdir=TB', file=cfg_file) + for f in cga.frames: + print('subgraph cluster_{} {{'.format(f.name), file=cfg_file) + print('label={};'.format(f.name), file=cfg_file) + print('color=lightgrey;', file=cfg_file) + print('style=filled;', file=cfg_file) + f.cfg.to_dot(cfg_file) + print('}', file=cfg_file) + print('}', file=cfg_file) + +def dump_ig(cga, ig_file): + print('digraph G {', file=ig_file) + print('edge [arrowhead=none]', file=ig_file) + for f in cga.frames: + print('subgraph cluster_{} {{'.format(f.name), file=ig_file) + print('label={};'.format(f.name), file=ig_file) + print('color=lightgrey;', file=ig_file) + print('style=filled;', file=ig_file) + f.ig.to_dot(ig_file) + print('}', file=ig_file) + print('}', file=ig_file) + +if __name__ == '__main__': + diag = ppci.DiagnosticsManager() + builder = c3.Builder(diag) + irc = builder.build(testsrc) + if not irc: + diag.printErrors(testsrc) + irc.check() + #irc.dump() + with open('ir.gv', 'w') as f: + ir.dumpgv(irc, f) + outs = outstream.TextOutputStream() + cga = codegenarm.ArmCodeGenerator(outs) + ir2 = cga.generate(irc) + + with open('cfg.gv', 'w') as cfg_file: + dump_cfg(cga, cfg_file) + + with open('ig.gv', 'w') as ig_file: + dump_ig(cga, ig_file) + + outs.dump() + diff -r bd2593de3ff8 -r 7b38782ed496 test/testasm.py --- a/test/testasm.py Thu Nov 21 15:46:50 2013 +0100 +++ b/test/testasm.py Sun Nov 24 11:24:15 2013 +0100 @@ -4,11 +4,11 @@ from ppci import CompilerError from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber from asm import tokenize, Assembler -import msp430 -import cortexm3 as arm +import target.armtarget as arm import outstream from target import Label + class AssemblerLexingCase(unittest.TestCase): """ Tests the assemblers lexer """ @@ -33,6 +33,7 @@ with self.assertRaises(CompilerError): list(tokenize(asmline)) + class AssemblerParsingTestCase(unittest.TestCase): """ Tests the assembler parts @@ -313,6 +314,4 @@ self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7') if __name__ == '__main__': - #cProfile.run('unittest.main()') unittest.main() - diff -r bd2593de3ff8 -r 7b38782ed496 test/testcg.py --- a/test/testcg.py Thu Nov 21 15:46:50 2013 +0100 +++ b/test/testcg.py Sun Nov 24 11:24:15 2013 +0100 @@ -4,6 +4,7 @@ import codegenarm import outstream + def genTestFunction(): m = ir.Module('tst') f = ir.Function('tst') @@ -38,4 +39,3 @@ if __name__ == '__main__': unittest.main() - diff -r bd2593de3ff8 -r 7b38782ed496 test/testgraph.py --- a/test/testgraph.py Thu Nov 21 15:46:50 2013 +0100 +++ b/test/testgraph.py Sun Nov 24 11:24:15 2013 +0100 @@ -40,7 +40,7 @@ class DigraphTestCase(unittest.TestCase): pass - + class InterferenceGraphTestCase(unittest.TestCase): def testNormalUse(self): @@ -78,4 +78,3 @@ if __name__ == '__main__': unittest.main() - diff -r bd2593de3ff8 -r 7b38782ed496 test/testmsp430asm.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testmsp430asm.py Sun Nov 24 11:24:15 2013 +0100 @@ -0,0 +1,49 @@ +#!/usr/bin/python + +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 testasm import AsmTestCaseBase + + +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) + + def testMov(self): + self.feed("mov r14, r15") + self.check('0F4E') + + def testMov1337(self): + self.feed("mov 0x1337, r12") + self.check('3C403713') + + def testAdd(self): + self.feed("add r15, r13") + self.check('0D5F') + + def testReti(self): + self.feed("reti") + self.check('0013') + + def testMSPinstructionCount(self): + """ Check that there are 27 instructions """ + self.assertEqual(27, len(self.t.instructions)) + + +if __name__ == '__main__': + unittest.main()