B
Bill Davy
The following code produces an error message (using Idle with Py 2.4 and
2.5). "There's an error in your program: EOL while scanning single-quoted
string". It comes just after "s = ''" (put there to try and isolate the
broken string).
It would be good if the error message pointed me to the start of said single
quoted string.
The colouring in IDLE does not indicate a bad string.
Puzzled.
Bill
#
# The traceback module is used to provide a stack trace to
# show the user where the error occured. See Error().
#
import traceback
#
# The math module is used to convert numbers between the Python real format
# and the Keil real format. See KeilToFloatingPoint() and FloatingToKeil().
#
import math
LOAD_LIT = 1
LOAD_REG = 1
STORE_REG = 1
ADD_LIT_FP = 2 + 8
ADD_LIT_INT = 2 + 16
ADD_REG_FP = 2 + 32
ADD_REG_INT = 9
SUB_LIT_FP = 11
SUB_LIT_INT = 12
SUB_REG_FP = 13
SUB_REG_INT =14
MUL_LIT_FP = 11
MUL_LIT_INT = 12
MUL_REG_FP = 13
MUL_REG_INT =14
DIV_LIT_FP = 11
DIV_LIT_INT = 12
DIV_REG_FP = 13
DIV_REG_INT =14
AND_LIT_INT = 12
AND_REG_INT =14
OR_LIT_INT = 12
OR_REG_INT =14
NEGATE_FP = 11
NEGATE_INT = 12
ABSOLUTE_FP = 13
ABSOLUTE_INT = 14
INVERT_INT = 15
JUMP_OPCODE = 15
JLT_OPCODE = 15
JGT_OPCODE = 15
JLE_OPCODE = 15
JGE_OPCODE = 15
JEQ_OPCODE = 15
JNE_OPCODE = 15
BinaryOps={
"LOAD":{float:{"L":LOAD_LIT,"R":LOAD_REG},int:{"L":LOAD_LIT,"R":LOAD_REG}},
"STORE":{float:{"R":STORE_REG},int:{"R":STORE_REG}},
"ADD":{float:{"L":ADD_LIT_FP,"R":ADD_REG_FP},int:{"L":ADD_LIT_INT,"R":ADD_REG_INT}},
"SUB":{float:{"L":SUB_LIT_FP,"R":SUB_REG_FP},int:{"L":SUB_LIT_INT,"R":SUB_REG_INT}},
"MUL":{float:{"L":MUL_LIT_FP,"R":MUL_REG_FP},int:{"L":MUL_LIT_INT,"R":MUL_REG_INT}},
"DIV":{float:{"L"IV_LIT_FP,"R"IV_REG_FP},int:{"L"IV_LIT_INT,"R"IV_REG_INT}},
"AND":{int:{"L":AND_LIT_INT,"R":AND_REG_INT}},
"OR":{int:{"L":OR_LIT_INT,"R":OR_REG_INT}}
}
UnaryOps={
"NEGATE":{float:NEGATE_FP, int:NEGATE_INT},
"ABSOLUTE":{float:ABSOLUTE_FP, int:ABSOLUTE_INT},
"INVERT":{int:INVERT_INT}
}
JumpOps={
"JUMP":JUMP_OPCODE,
"JLT":JLT_OPCODE,
"JGT":JGT_OPCODE,
"JLE":JLE_OPCODE,
"JGE":JGE_OPCODE,
"JEQ":JEQ_OPCODE,
"JNE":JNE_OPCODE
}
def IsOpCode(s):
if ( s in BinaryOps ): return True;
if ( s in UnaryOps ): return True;
if ( s in JumpOps ): return True;
return False
class Register:
"""
This class provides us with a register (say) 0..32
In addtion to a number, a register can be given a name.
It allows LOAD(arg) and other opcodes to distinguish between
references to a register and a literal value.
"""
def __init__(self,Id,Name=None):
self.Number = Id
if ( Name == None):
self.Name = "R%d" % Id
else:
self.Name = Name
def RegisterNumber(self):
return self.Number
def RegisterName(self):
return self.Name
R0=Register(0)
R1=Register(1)
R2=Register(2)
Now=Register(2,"Now")
def IsRegister(arg):
return hasattr( arg, "RegisterNumber")
assert not IsRegister(0)
assert not IsRegister(1.2)
assert IsRegister(R1)
assert IsRegister(Now)
#
# ErrorCount is global as it is shared by all slaves.
#
ErrorCount = 0
def Error(Message):
"""
work back through the traceback until you find a function whose name is
in one of the
opcode dictionaries and trace back from there. This will keep internal
implemenataion functions private but still allow the suer to define
functions
that generate code.
"""
global ErrorCount
ErrorCount += 1
"""
[
('<string>', 1, '?', None),
('C:\\Python24\\lib\\idlelib\\run.py', 90, 'main', 'ret = method(*args,
**kwargs)'),
('C:\\Python24\\lib\\idlelib\\run.py', 283, 'runcode', 'exec code in
self.locals'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 434, '?', 'STORE(1)'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 147, 'STORE',
'self.BINOP("STORE",Arg,Msg)'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 198, 'BINOP', 'return
Error("Cannot perform %s on %s" % (Op,Arg))'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 106, 'Error', 'tb =
traceback.extract_stack()')
]
"""
tb = traceback.extract_stack()
BeforePrinting = True
IsPrinting = False
for i in range(len(tb)-1,0,-1):
frame = tb
if ( BeforePrinting ):
# Looking to start
if IsOpCode(frame[2]): # start printing
IsPrinting = True
BeforePrinting = False
print "John: %s\nTrace back follows:" % Message
elif ( IsPrinting ):
print '\tFile "%s", line %u, %s' % (frame[0], frame[1],
frame[3])
# Stop when we find the curious function "?"
if (frame[2] == "?"):
break
if BeforePrinting:
print "John: %s (no trace back)" % Message
class Slave:
"This is a slave class"
Listing = ""
Number = 0
Mode = 0; # Will be int or float when defined
def __init__(self,Id):
self.Number = Id
self.Line = 0
#
# The listing, built as we go along
#
self.Listing = ""
self.Mode = None
def SetMode(self, arg):
self.Mode = arg
def LOAD(self,Arg,Msg=""):
self.BINOP("LOAD",Arg,Msg)
def STORE(self,Arg,Msg=""):
self.BINOP("STORE",Arg,Msg)
def ADD(self,Arg,Msg=""):
self.BINOP("ADD",Arg,Msg)
def SUB(self,Arg,Msg=""):
self.BINOP("SUB",Arg,Msg)
def MUL(self,Arg,Msg=""):
self.BINOP("MUL",Arg,Msg)
def DIV(self,Arg,Msg=""):
self.BINOP("DIV",Arg,Msg)
def AND(self,Arg,Msg=""):
self.BINOP("AND",Arg,Msg)
def OR(self,Arg,Msg=""):
selfBINOPOP("OR",Arg,Msg)
def NEGATE(self,Msg=""):
self.UNOP("NEGATE",Msg)
def ABSOLUTE(self,Msg=""):
self.UNOP("ABSOLUTE",Msg)
def INVERT(self,Msg=""):
self.UNOP("INVERT",Msg)
def JUMP(self,Arg,Msg=""):
self.JUMPOP("JUMP",Arg,Msg)
def JLT(self,Arg,Msg=""):
self.JUMPOP("JLT",Arg,Msg)
def JGT(self,Arg,Msg=""):
self.JUMPOP("JGT",Arg,Msg)
def JLE(self,Arg,Msg=""):
self.JUMPOP("JLE",Arg,Msg)
def JGE(self,Arg,Msg=""):
self.JUMPOP("JGE",Arg,Msg)
def JEQ(self,Arg,Msg=""):
self.JUMPOP("JEQ",Arg,Msg)
def JNE(self,Arg,Msg=""):
self.JUMPOP("JNE",Arg,Msg)
def BINOP(self,Op,Arg,Msg):
entry = BinaryOps.get(Op)
assert entry != None, "Who gave me %s to look up?" % op
entry = entry.get(self.Mode)
if entry == None :
return Error("Cannot perform %s on %s, mode=%s" % (
Op,Arg,self.Mode))
if ( IsRegister(Arg) ):
ot = entry.get("R") # Register
if ot == None:
return Error("Cannot perform %s on %s" % (Op,Arg))
self.Listing += "%x \t \t%s\t%s\t# %s\n" % (
len(self.Memory), Op,Arg.RegisterName(), Msg)
self.Memory.append(ot)
self.Memory.append(Arg.RegisterNumber())
else:
ot = entry.get("L") # Literal
if ot == None:
return Error("Cannot perform %s on %s" % (Op,Arg))
self.Listing += "%x \t \t%s\t%s\t# %s\n" % (
len(self.Memory), Op, Arg, Msg)
self.Memory.append(ot)
cArg = self.Mode(Arg)
if self.Mode == int:
try:
iArg = int(Arg)
except TypeError:
return Error("Argument %r is not an integer" % Arg)
except:
return Error("Unexpected error:", sys.exc_info()[0])
if ( iArg != Arg ):
return Error("Argument %r is not an integer" % Arg)
self.Memory.append((iArg >> 24) & 0xFF)
self.Memory.append((iArg >> 16) & 0xFF)
self.Memory.append((iArg >> 8) & 0xFF)
self.Memory.append((iArg >> 0) & 0xFF)
elif self.Mode == float:
try:
fArg = float(Arg)
except TypeError:
return Error("Argument %r is not a float" % Arg)
except:
return Error("Unexpected error:", sys.exc_info()[0])
if ( fArg != Arg ):
return Error("Argument %r is not a float" % Arg)
FourBytes = FloatingToKeil(fArg)
self.Memory.append(FourBytes[0])
self.Memory.append(FourBytes[1])
self.Memory.append(FourBytes[2])
self.Memory.append(FourBytes[3])
else:
return Error("No or bad mode (%r)set for slave %u" % (
self.Mode,self.SlaveNumber))
def JUMPOP(self,Op,Name,Msg):
entry = JumpOps.get(Op)
assert entry != None, "Who gave me %s to look up?" % op
"""
Generate code for a jump to the given target
May enter target into the table.
"""
self.Listing += "%x \t \t%s\t%s\t# %s\n" % (
len(self.Memory),Op,Name, Msg)
self.Memory.append(entry)
self.AddReference(Name,len(self.Memory)) # for patching up later
self.Memory.append(0) # Space for destination of jump
#
# The memory image of this Slave.
#
Memory = []
def ListProgram(self):
"""Generate a user friendly listing of the program for this Slave.
""""
s = ''
print "%s" % self.Number
print "%s\n" % ("#" * 64)
print "%s" % self.Listing
pass
def EmitProgram(self):
"""Emit a C code data structure of the program for this Slave.
"""
s=\
"%s\n/* C data structure for slave %d */\n"\
"struct\n"\
"\t{\n"\
"\tunsigned SlaveId;\n"\
"\tunsigned nBytes;\n"\
"\tunsigned char[%d];\n"\
"\t} Slave%d=\n"\
"\t{%u,%u\n"\
"\t{\n\t"\
% ('#'*64, self.Number, len(self.Memory), self.Number, self.Number,
len(self.Memory))
for i in range(0,len(self.Memory)):
if (i>0) : s+= ", "
s += "0x%x" % (self.Memory)
if ( (i % 16) == 15 ):
s += '\n\t'
s+="\n\t}\n\t};\n"
print s;
#
# Dictionary of Labels
# Maps Name onto (Set of Locations, List of references))
# Users define a label using Label(Name)
# Users reference a label using Jump(Name)
#
LabelTable = {}
def AddReference(self,Name,Reference):
"""
Add a reference to the given Name.
Name may not yet be defined
"""
Entry = self.LabelTable.get(Name)
if ( Entry == None ):
self.LabelTable[Name] = [ [] , [Reference] ]
else:
Entry[1].append(Reference)
def AddDefinition(self,Name,Location):
"""
Add a definition to the given Name.
Name may not yet be defined.
If it is defined, it may not be given a different Location.
"""
Entry = self.LabelTable.get(Name)
if ( Entry == None ):
# Add location to a new name
self.LabelTable[Name] = [ [Location] , [] ]
elif len(Entry[0]) == 0:
# Provide an initial location for a known name
Entry[0].append(Location)
elif Entry[0].count(Location) == 1:
# The same location, harmless but odd
pass
else:
# This is an additional definition but that does not matter
# unless it is used and we find that out when we call
FixUpLabels()
# at the end.
Entry[0].append(Location)
def Label(self, Name, Msg=""):
"""
Lays down a label for the user.
"""
self.AddDefinition(Name,len(self.Memory))
self.Listing += "%x \t%s: \t \t \t# %s\n" % (len(self.Memory), Name,
Msg)
def EmitLabelTable(self):
print "%s\nSymbol table for Slave %u" % ('#' * 64, self.Number)
for Name in self.LabelTable.keys():
s = "Name=%s" % Name
entry = self.LabelTable[Name]
if ( len(entry[0])==1 and len(entry[1]) == 0):
s += ", is not referenced"
if ( len(entry[0])==0 and len(entry[1]) > 0):
s += ", is not defined"
if ( len(entry[0])>1 and len(entry[1]) > 0):
s += ", is multiply-defined"
if ( len(entry[0]) > 0):
s += ", Location:"
for i in entry[0]:
s += " %x" % i
if ( len(entry[1]) > 0 ):
s += ", references:"
for i in range(0,len(entry[1])):
s += " %x" % entry[1]
print s
def FixUpLabels(self):
print "%s\nFixing labels for Slave %u" % ('#' * 64, self.Number)
for Name in self.LabelTable.keys():
entry = self.LabelTable[Name]
if ( len(entry[0])==1 and len(entry[1]) == 0):
print "Warning: %s is not referenced" % Name
elif ( len(entry[0])==0 and len(entry[1]) > 0):
Error("%s is not defined" % Name)
elif ( len(entry[0])>1 and len(entry[1]) > 0):
Error("%s is multiply-defined" % Name)
else:
for i in range(0,len(entry[1])):
self.Memory[entry[1]] = entry[0][0]
#
# Construct a vector of Slaves
#
S=[(Slave(i)) for i in range(6)]
def SetSlave(New):
"""
Make global functions generate code for a specified slave.
"""
#
# This sets the mode for the assembler and applies in the order of
# assembly, not in the execution order. The mode is embedded in the
opcode.
#
global SetMode
SetMode = S[New].SetMode
#
# Labels are local to a slave.
#
global Label
Label = S[New].Label;
global LOAD, STORE, ADD, SUB, MUL, DIV, AND, OR
global NEGATE, ABSOLUTE, INVERT
global JUMP, JLT, JGT, JLE, JGE, JEQ, JNE
LOAD = S[New].LOAD
JUMP = S[New].JUMP
LOAD = S[New].LOAD
STORE = S[New].STORE
ADD = S[New].ADD
SUB = S[New].SUB
MUL = S[New].MUL
DIV = S[New].DIV
AND = S[New].AND
OR = S[New].OR
NEGATE = S[New].NEGATE
ABSOLUTE = S[New].ABSOLUTE
INVERT = S[New].INVERT
JUMP = S[New].JUMP
JLT = S[New].JLT
JGT = S[New].JGT
JLE = S[New].JLE
JGE = S[New].JGE
JEQ = S[New].JEQ
JNE = S[New].JNE
print "hi"
SetSlave(1)
SetMode(int)
LOAD(4,"Into S1 hopefully")
Label("Loop")
LOAD(R1,"Comment")
JUMP("Loop")
LOAD(Now)
JUMP("Loop")
STORE(1)
Label("Loop")
class TemporaryLabelClass:
DefaultBaseName = "TL_"
Instances = {DefaultBaseName:0}
def __init__(self, BaseName=None):
de = self.Instances.get(BaseName)
if de == None:
self.Instances[BaseName] = 0 # new temporary BaseName
else:
self.Instances[BaseName] += 1 # using an existing BaseName again
self.BaseName = BaseName;
def Instance(self):
return self.Instances[self.BaseName]
def TemporaryLabel(BaseName=None):
t = TemporaryLabelClass(BaseName)
if ( BaseName == None ):
BaseName = t.DefaultBaseName
elif ( BaseName == t.DefaultBaseName):
return Error("Do not call TemporaryLabel(%s)" % t.DefaultBaseName)
return "%s%u" % (BaseName,t.Instance())
a = TemporaryLabel()
b = TemporaryLabel("MY")
c = TemporaryLabel()
d = TemporaryLabel("MY")
e = TemporaryLabel()
f = TemporaryLabel("TL_")
del a, b, c, d, e, f
def BusyIdleLoop(Time, Register):
label = TemporaryLabel()
LOAD(Now)
ADD(Time)
STORE(Register)
Label(label)
LOAD(Now)
SUB(Register)
JLT(label)
BusyIdleLoop(5000,R0)
S[1].FixUpLabels()
S[1].EmitProgram()
S[1].EmitLabelTable()
S[1].ListProgram()
def KeilToFloatingPoint(Bytes):
#print Bytes
temp = ((((((Bytes[0]<<8)+Bytes[1])<<8)+Bytes[2])<<8)+Bytes[3])
if ( temp == 0):
return 0.0
Mantissa = 0x800000 + (temp&0x7fffff)
if ( temp & 0x80000000 ):
Mantissa = -Mantissa
temp -= 0x80000000
Exponent = (0xFF & (temp>>23)) - 127;
Mantissa = float(Mantissa) / (1<<23)
#print "Mantissa=%f" % Mantissa
#print "Exponent=%x" % Exponent
return math.ldexp(Mantissa, Exponent)
def FloatingToKeil(arg):
"""
The flooating point format used by Keil follows
the IEEE-754 standard
The fields are (from MSB to LSB, and first byte to last):
S (one bit) 1 is posirtive, 0 is negative
E (eight bits) Exponent + 127
M (23 bits) The twenty four bit (MSB omitted) mantissa
"""
Mantissa, Exponent = math.frexp( arg )
Mantissa *= 2
Exponent -= 1
if ( Mantissa >= 0 ):
if ( Exponent == 0 ):
return (0,0,0,0)
S = 0
else:
S = 1
Mantissa = -Mantissa
Mantissa *= (1<<23)
Mantissa = int(Mantissa + 0.5) # round
if ( Mantissa >> 24 ):
# Renormalise
Mantissa >>= 1
Exponent += 1
assert ( (Mantissa >> 24) == 0)
Mantissa -= (1<<23) # Remove the "assumed" 1 before the binary point
assert ( (Mantissa >> 23) == 0 )
Exponent += 127
if ( Exponent < 0 ):
# Number is too small to represent; call it zero
FourBytes = 0,0,0,0
temp = KeilToFloatingPoint(FourBytes)
print "Truncating %r to %r" % (arg, temp)
elif ( Exponent > 0xFF):
# Number is too big to represent; make the maximum with the right
sign
FourBytes = (S<<7)+0x7F,0xFF,0xFF,0xFF
temp = KeilToFloatingPoint(FourBytes)
print "Truncating %r to %r" % (arg, temp)
else:
temp = (S<<31) + (Exponent<<23) + Mantissa
FourBytes = ((temp>>24),0xFF&(temp>>16),0xFF&(temp>>8),0xFF&(temp))
temp = KeilToFloatingPoint(FourBytes)
return FourBytes
FloatingToKeil(-12.5)
FloatingToKeil(-1e-200) ## should become zero
FloatingToKeil(-1e+200) ## should saturate
FloatingToKeil(math.ldexp((1<<24)-1,-24)) ## Exact conversion
FloatingToKeil(math.ldexp((1<<25)-1,-25)) ## Should make renormalise happen
print "Byeee"
2.5). "There's an error in your program: EOL while scanning single-quoted
string". It comes just after "s = ''" (put there to try and isolate the
broken string).
It would be good if the error message pointed me to the start of said single
quoted string.
The colouring in IDLE does not indicate a bad string.
Puzzled.
Bill
#
# The traceback module is used to provide a stack trace to
# show the user where the error occured. See Error().
#
import traceback
#
# The math module is used to convert numbers between the Python real format
# and the Keil real format. See KeilToFloatingPoint() and FloatingToKeil().
#
import math
LOAD_LIT = 1
LOAD_REG = 1
STORE_REG = 1
ADD_LIT_FP = 2 + 8
ADD_LIT_INT = 2 + 16
ADD_REG_FP = 2 + 32
ADD_REG_INT = 9
SUB_LIT_FP = 11
SUB_LIT_INT = 12
SUB_REG_FP = 13
SUB_REG_INT =14
MUL_LIT_FP = 11
MUL_LIT_INT = 12
MUL_REG_FP = 13
MUL_REG_INT =14
DIV_LIT_FP = 11
DIV_LIT_INT = 12
DIV_REG_FP = 13
DIV_REG_INT =14
AND_LIT_INT = 12
AND_REG_INT =14
OR_LIT_INT = 12
OR_REG_INT =14
NEGATE_FP = 11
NEGATE_INT = 12
ABSOLUTE_FP = 13
ABSOLUTE_INT = 14
INVERT_INT = 15
JUMP_OPCODE = 15
JLT_OPCODE = 15
JGT_OPCODE = 15
JLE_OPCODE = 15
JGE_OPCODE = 15
JEQ_OPCODE = 15
JNE_OPCODE = 15
BinaryOps={
"LOAD":{float:{"L":LOAD_LIT,"R":LOAD_REG},int:{"L":LOAD_LIT,"R":LOAD_REG}},
"STORE":{float:{"R":STORE_REG},int:{"R":STORE_REG}},
"ADD":{float:{"L":ADD_LIT_FP,"R":ADD_REG_FP},int:{"L":ADD_LIT_INT,"R":ADD_REG_INT}},
"SUB":{float:{"L":SUB_LIT_FP,"R":SUB_REG_FP},int:{"L":SUB_LIT_INT,"R":SUB_REG_INT}},
"MUL":{float:{"L":MUL_LIT_FP,"R":MUL_REG_FP},int:{"L":MUL_LIT_INT,"R":MUL_REG_INT}},
"DIV":{float:{"L"IV_LIT_FP,"R"IV_REG_FP},int:{"L"IV_LIT_INT,"R"IV_REG_INT}},
"AND":{int:{"L":AND_LIT_INT,"R":AND_REG_INT}},
"OR":{int:{"L":OR_LIT_INT,"R":OR_REG_INT}}
}
UnaryOps={
"NEGATE":{float:NEGATE_FP, int:NEGATE_INT},
"ABSOLUTE":{float:ABSOLUTE_FP, int:ABSOLUTE_INT},
"INVERT":{int:INVERT_INT}
}
JumpOps={
"JUMP":JUMP_OPCODE,
"JLT":JLT_OPCODE,
"JGT":JGT_OPCODE,
"JLE":JLE_OPCODE,
"JGE":JGE_OPCODE,
"JEQ":JEQ_OPCODE,
"JNE":JNE_OPCODE
}
def IsOpCode(s):
if ( s in BinaryOps ): return True;
if ( s in UnaryOps ): return True;
if ( s in JumpOps ): return True;
return False
class Register:
"""
This class provides us with a register (say) 0..32
In addtion to a number, a register can be given a name.
It allows LOAD(arg) and other opcodes to distinguish between
references to a register and a literal value.
"""
def __init__(self,Id,Name=None):
self.Number = Id
if ( Name == None):
self.Name = "R%d" % Id
else:
self.Name = Name
def RegisterNumber(self):
return self.Number
def RegisterName(self):
return self.Name
R0=Register(0)
R1=Register(1)
R2=Register(2)
Now=Register(2,"Now")
def IsRegister(arg):
return hasattr( arg, "RegisterNumber")
assert not IsRegister(0)
assert not IsRegister(1.2)
assert IsRegister(R1)
assert IsRegister(Now)
#
# ErrorCount is global as it is shared by all slaves.
#
ErrorCount = 0
def Error(Message):
"""
work back through the traceback until you find a function whose name is
in one of the
opcode dictionaries and trace back from there. This will keep internal
implemenataion functions private but still allow the suer to define
functions
that generate code.
"""
global ErrorCount
ErrorCount += 1
"""
[
('<string>', 1, '?', None),
('C:\\Python24\\lib\\idlelib\\run.py', 90, 'main', 'ret = method(*args,
**kwargs)'),
('C:\\Python24\\lib\\idlelib\\run.py', 283, 'runcode', 'exec code in
self.locals'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 434, '?', 'STORE(1)'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 147, 'STORE',
'self.BINOP("STORE",Arg,Msg)'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 198, 'BINOP', 'return
Error("Cannot perform %s on %s" % (Op,Arg))'),
('H:\\Husky Experiments\\Viper1\\tmp.py', 106, 'Error', 'tb =
traceback.extract_stack()')
]
"""
tb = traceback.extract_stack()
BeforePrinting = True
IsPrinting = False
for i in range(len(tb)-1,0,-1):
frame = tb
if ( BeforePrinting ):
# Looking to start
if IsOpCode(frame[2]): # start printing
IsPrinting = True
BeforePrinting = False
print "John: %s\nTrace back follows:" % Message
elif ( IsPrinting ):
print '\tFile "%s", line %u, %s' % (frame[0], frame[1],
frame[3])
# Stop when we find the curious function "?"
if (frame[2] == "?"):
break
if BeforePrinting:
print "John: %s (no trace back)" % Message
class Slave:
"This is a slave class"
Listing = ""
Number = 0
Mode = 0; # Will be int or float when defined
def __init__(self,Id):
self.Number = Id
self.Line = 0
#
# The listing, built as we go along
#
self.Listing = ""
self.Mode = None
def SetMode(self, arg):
self.Mode = arg
def LOAD(self,Arg,Msg=""):
self.BINOP("LOAD",Arg,Msg)
def STORE(self,Arg,Msg=""):
self.BINOP("STORE",Arg,Msg)
def ADD(self,Arg,Msg=""):
self.BINOP("ADD",Arg,Msg)
def SUB(self,Arg,Msg=""):
self.BINOP("SUB",Arg,Msg)
def MUL(self,Arg,Msg=""):
self.BINOP("MUL",Arg,Msg)
def DIV(self,Arg,Msg=""):
self.BINOP("DIV",Arg,Msg)
def AND(self,Arg,Msg=""):
self.BINOP("AND",Arg,Msg)
def OR(self,Arg,Msg=""):
selfBINOPOP("OR",Arg,Msg)
def NEGATE(self,Msg=""):
self.UNOP("NEGATE",Msg)
def ABSOLUTE(self,Msg=""):
self.UNOP("ABSOLUTE",Msg)
def INVERT(self,Msg=""):
self.UNOP("INVERT",Msg)
def JUMP(self,Arg,Msg=""):
self.JUMPOP("JUMP",Arg,Msg)
def JLT(self,Arg,Msg=""):
self.JUMPOP("JLT",Arg,Msg)
def JGT(self,Arg,Msg=""):
self.JUMPOP("JGT",Arg,Msg)
def JLE(self,Arg,Msg=""):
self.JUMPOP("JLE",Arg,Msg)
def JGE(self,Arg,Msg=""):
self.JUMPOP("JGE",Arg,Msg)
def JEQ(self,Arg,Msg=""):
self.JUMPOP("JEQ",Arg,Msg)
def JNE(self,Arg,Msg=""):
self.JUMPOP("JNE",Arg,Msg)
def BINOP(self,Op,Arg,Msg):
entry = BinaryOps.get(Op)
assert entry != None, "Who gave me %s to look up?" % op
entry = entry.get(self.Mode)
if entry == None :
return Error("Cannot perform %s on %s, mode=%s" % (
Op,Arg,self.Mode))
if ( IsRegister(Arg) ):
ot = entry.get("R") # Register
if ot == None:
return Error("Cannot perform %s on %s" % (Op,Arg))
self.Listing += "%x \t \t%s\t%s\t# %s\n" % (
len(self.Memory), Op,Arg.RegisterName(), Msg)
self.Memory.append(ot)
self.Memory.append(Arg.RegisterNumber())
else:
ot = entry.get("L") # Literal
if ot == None:
return Error("Cannot perform %s on %s" % (Op,Arg))
self.Listing += "%x \t \t%s\t%s\t# %s\n" % (
len(self.Memory), Op, Arg, Msg)
self.Memory.append(ot)
cArg = self.Mode(Arg)
if self.Mode == int:
try:
iArg = int(Arg)
except TypeError:
return Error("Argument %r is not an integer" % Arg)
except:
return Error("Unexpected error:", sys.exc_info()[0])
if ( iArg != Arg ):
return Error("Argument %r is not an integer" % Arg)
self.Memory.append((iArg >> 24) & 0xFF)
self.Memory.append((iArg >> 16) & 0xFF)
self.Memory.append((iArg >> 8) & 0xFF)
self.Memory.append((iArg >> 0) & 0xFF)
elif self.Mode == float:
try:
fArg = float(Arg)
except TypeError:
return Error("Argument %r is not a float" % Arg)
except:
return Error("Unexpected error:", sys.exc_info()[0])
if ( fArg != Arg ):
return Error("Argument %r is not a float" % Arg)
FourBytes = FloatingToKeil(fArg)
self.Memory.append(FourBytes[0])
self.Memory.append(FourBytes[1])
self.Memory.append(FourBytes[2])
self.Memory.append(FourBytes[3])
else:
return Error("No or bad mode (%r)set for slave %u" % (
self.Mode,self.SlaveNumber))
def JUMPOP(self,Op,Name,Msg):
entry = JumpOps.get(Op)
assert entry != None, "Who gave me %s to look up?" % op
"""
Generate code for a jump to the given target
May enter target into the table.
"""
self.Listing += "%x \t \t%s\t%s\t# %s\n" % (
len(self.Memory),Op,Name, Msg)
self.Memory.append(entry)
self.AddReference(Name,len(self.Memory)) # for patching up later
self.Memory.append(0) # Space for destination of jump
#
# The memory image of this Slave.
#
Memory = []
def ListProgram(self):
"""Generate a user friendly listing of the program for this Slave.
""""
s = ''
print "%s" % self.Number
print "%s\n" % ("#" * 64)
print "%s" % self.Listing
pass
def EmitProgram(self):
"""Emit a C code data structure of the program for this Slave.
"""
s=\
"%s\n/* C data structure for slave %d */\n"\
"struct\n"\
"\t{\n"\
"\tunsigned SlaveId;\n"\
"\tunsigned nBytes;\n"\
"\tunsigned char[%d];\n"\
"\t} Slave%d=\n"\
"\t{%u,%u\n"\
"\t{\n\t"\
% ('#'*64, self.Number, len(self.Memory), self.Number, self.Number,
len(self.Memory))
for i in range(0,len(self.Memory)):
if (i>0) : s+= ", "
s += "0x%x" % (self.Memory)
if ( (i % 16) == 15 ):
s += '\n\t'
s+="\n\t}\n\t};\n"
print s;
#
# Dictionary of Labels
# Maps Name onto (Set of Locations, List of references))
# Users define a label using Label(Name)
# Users reference a label using Jump(Name)
#
LabelTable = {}
def AddReference(self,Name,Reference):
"""
Add a reference to the given Name.
Name may not yet be defined
"""
Entry = self.LabelTable.get(Name)
if ( Entry == None ):
self.LabelTable[Name] = [ [] , [Reference] ]
else:
Entry[1].append(Reference)
def AddDefinition(self,Name,Location):
"""
Add a definition to the given Name.
Name may not yet be defined.
If it is defined, it may not be given a different Location.
"""
Entry = self.LabelTable.get(Name)
if ( Entry == None ):
# Add location to a new name
self.LabelTable[Name] = [ [Location] , [] ]
elif len(Entry[0]) == 0:
# Provide an initial location for a known name
Entry[0].append(Location)
elif Entry[0].count(Location) == 1:
# The same location, harmless but odd
pass
else:
# This is an additional definition but that does not matter
# unless it is used and we find that out when we call
FixUpLabels()
# at the end.
Entry[0].append(Location)
def Label(self, Name, Msg=""):
"""
Lays down a label for the user.
"""
self.AddDefinition(Name,len(self.Memory))
self.Listing += "%x \t%s: \t \t \t# %s\n" % (len(self.Memory), Name,
Msg)
def EmitLabelTable(self):
print "%s\nSymbol table for Slave %u" % ('#' * 64, self.Number)
for Name in self.LabelTable.keys():
s = "Name=%s" % Name
entry = self.LabelTable[Name]
if ( len(entry[0])==1 and len(entry[1]) == 0):
s += ", is not referenced"
if ( len(entry[0])==0 and len(entry[1]) > 0):
s += ", is not defined"
if ( len(entry[0])>1 and len(entry[1]) > 0):
s += ", is multiply-defined"
if ( len(entry[0]) > 0):
s += ", Location:"
for i in entry[0]:
s += " %x" % i
if ( len(entry[1]) > 0 ):
s += ", references:"
for i in range(0,len(entry[1])):
s += " %x" % entry[1]
print s
def FixUpLabels(self):
print "%s\nFixing labels for Slave %u" % ('#' * 64, self.Number)
for Name in self.LabelTable.keys():
entry = self.LabelTable[Name]
if ( len(entry[0])==1 and len(entry[1]) == 0):
print "Warning: %s is not referenced" % Name
elif ( len(entry[0])==0 and len(entry[1]) > 0):
Error("%s is not defined" % Name)
elif ( len(entry[0])>1 and len(entry[1]) > 0):
Error("%s is multiply-defined" % Name)
else:
for i in range(0,len(entry[1])):
self.Memory[entry[1]] = entry[0][0]
#
# Construct a vector of Slaves
#
S=[(Slave(i)) for i in range(6)]
def SetSlave(New):
"""
Make global functions generate code for a specified slave.
"""
#
# This sets the mode for the assembler and applies in the order of
# assembly, not in the execution order. The mode is embedded in the
opcode.
#
global SetMode
SetMode = S[New].SetMode
#
# Labels are local to a slave.
#
global Label
Label = S[New].Label;
global LOAD, STORE, ADD, SUB, MUL, DIV, AND, OR
global NEGATE, ABSOLUTE, INVERT
global JUMP, JLT, JGT, JLE, JGE, JEQ, JNE
LOAD = S[New].LOAD
JUMP = S[New].JUMP
LOAD = S[New].LOAD
STORE = S[New].STORE
ADD = S[New].ADD
SUB = S[New].SUB
MUL = S[New].MUL
DIV = S[New].DIV
AND = S[New].AND
OR = S[New].OR
NEGATE = S[New].NEGATE
ABSOLUTE = S[New].ABSOLUTE
INVERT = S[New].INVERT
JUMP = S[New].JUMP
JLT = S[New].JLT
JGT = S[New].JGT
JLE = S[New].JLE
JGE = S[New].JGE
JEQ = S[New].JEQ
JNE = S[New].JNE
print "hi"
SetSlave(1)
SetMode(int)
LOAD(4,"Into S1 hopefully")
Label("Loop")
LOAD(R1,"Comment")
JUMP("Loop")
LOAD(Now)
JUMP("Loop")
STORE(1)
Label("Loop")
class TemporaryLabelClass:
DefaultBaseName = "TL_"
Instances = {DefaultBaseName:0}
def __init__(self, BaseName=None):
de = self.Instances.get(BaseName)
if de == None:
self.Instances[BaseName] = 0 # new temporary BaseName
else:
self.Instances[BaseName] += 1 # using an existing BaseName again
self.BaseName = BaseName;
def Instance(self):
return self.Instances[self.BaseName]
def TemporaryLabel(BaseName=None):
t = TemporaryLabelClass(BaseName)
if ( BaseName == None ):
BaseName = t.DefaultBaseName
elif ( BaseName == t.DefaultBaseName):
return Error("Do not call TemporaryLabel(%s)" % t.DefaultBaseName)
return "%s%u" % (BaseName,t.Instance())
a = TemporaryLabel()
b = TemporaryLabel("MY")
c = TemporaryLabel()
d = TemporaryLabel("MY")
e = TemporaryLabel()
f = TemporaryLabel("TL_")
del a, b, c, d, e, f
def BusyIdleLoop(Time, Register):
label = TemporaryLabel()
LOAD(Now)
ADD(Time)
STORE(Register)
Label(label)
LOAD(Now)
SUB(Register)
JLT(label)
BusyIdleLoop(5000,R0)
S[1].FixUpLabels()
S[1].EmitProgram()
S[1].EmitLabelTable()
S[1].ListProgram()
def KeilToFloatingPoint(Bytes):
#print Bytes
temp = ((((((Bytes[0]<<8)+Bytes[1])<<8)+Bytes[2])<<8)+Bytes[3])
if ( temp == 0):
return 0.0
Mantissa = 0x800000 + (temp&0x7fffff)
if ( temp & 0x80000000 ):
Mantissa = -Mantissa
temp -= 0x80000000
Exponent = (0xFF & (temp>>23)) - 127;
Mantissa = float(Mantissa) / (1<<23)
#print "Mantissa=%f" % Mantissa
#print "Exponent=%x" % Exponent
return math.ldexp(Mantissa, Exponent)
def FloatingToKeil(arg):
"""
The flooating point format used by Keil follows
the IEEE-754 standard
The fields are (from MSB to LSB, and first byte to last):
S (one bit) 1 is posirtive, 0 is negative
E (eight bits) Exponent + 127
M (23 bits) The twenty four bit (MSB omitted) mantissa
"""
Mantissa, Exponent = math.frexp( arg )
Mantissa *= 2
Exponent -= 1
if ( Mantissa >= 0 ):
if ( Exponent == 0 ):
return (0,0,0,0)
S = 0
else:
S = 1
Mantissa = -Mantissa
Mantissa *= (1<<23)
Mantissa = int(Mantissa + 0.5) # round
if ( Mantissa >> 24 ):
# Renormalise
Mantissa >>= 1
Exponent += 1
assert ( (Mantissa >> 24) == 0)
Mantissa -= (1<<23) # Remove the "assumed" 1 before the binary point
assert ( (Mantissa >> 23) == 0 )
Exponent += 127
if ( Exponent < 0 ):
# Number is too small to represent; call it zero
FourBytes = 0,0,0,0
temp = KeilToFloatingPoint(FourBytes)
print "Truncating %r to %r" % (arg, temp)
elif ( Exponent > 0xFF):
# Number is too big to represent; make the maximum with the right
sign
FourBytes = (S<<7)+0x7F,0xFF,0xFF,0xFF
temp = KeilToFloatingPoint(FourBytes)
print "Truncating %r to %r" % (arg, temp)
else:
temp = (S<<31) + (Exponent<<23) + Mantissa
FourBytes = ((temp>>24),0xFF&(temp>>16),0xFF&(temp>>8),0xFF&(temp))
temp = KeilToFloatingPoint(FourBytes)
return FourBytes
FloatingToKeil(-12.5)
FloatingToKeil(-1e-200) ## should become zero
FloatingToKeil(-1e+200) ## should saturate
FloatingToKeil(math.ldexp((1<<24)-1,-24)) ## Exact conversion
FloatingToKeil(math.ldexp((1<<25)-1,-25)) ## Should make renormalise happen
print "Byeee"