summaryrefslogtreecommitdiff
path: root/pp2cc.py
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-11-30 23:18:10 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-11-30 23:18:10 +0000
commit9e797458dd8d144544564674a8767c077ed4bd39 (patch)
treed91b68e37c166b01c712a7b5ed9b2a87d29d68f4 /pp2cc.py
parentf8c1ccfac7fc22ba7d316a5b25ee58cd4d26a031 (diff)
downloadpp2cc-9e797458dd8d144544564674a8767c077ed4bd39.tar.gz
Support for all assignment except shifting, fix rightshift bug
Diffstat (limited to 'pp2cc.py')
-rwxr-xr-xpp2cc.py56
1 files changed, 39 insertions, 17 deletions
diff --git a/pp2cc.py b/pp2cc.py
index 6e6e614..6217f41 100755
--- a/pp2cc.py
+++ b/pp2cc.py
@@ -441,7 +441,7 @@ class Parse(object):
# word size in bits
self.WORDSIZE = 18
# preload operators and their instructions
- self.binary_ops = {
+ self.math_ops = {
"+": "ADD",
"-": "SUB",
"*": "MULS",
@@ -459,6 +459,7 @@ class Parse(object):
"==": "BEQ",
"!=": "BNE"
}
+ self.binary_ops = self.math_ops
self.binary_ops.update(self.comparison_ops)
# local and global variable names to be defined in @DATA
@@ -718,21 +719,27 @@ class Parse(object):
else:
# because DIV works with signed numbers, right shift is
# a bit harder because the sign bit does not vanish
- lbl_make_positive = self.uniqLbl("shiftPositive")
- lines.append(self.asm.binary_op("CMP", reg_first, 0))
- # if it's positive, skip handling for negative values
- lines.append(self.asm.branch_op("BPL", lbl_make_positive))
- # -1 / 2 = 0, so make sure that the last bit is zero
+ # Assume 4-bit numbers in the next example.
+ # binary | decimal
+ # 1111 | -1
+ # 0111 | 7
+ # The rightmost bit is insignificant in a right shift
+ # but causes issues with division by two for -1 because
+ # it gets rounded to 0. After removal of the rightmost
+ # bit and division by two, all bits are shifted left,
+ # but the result is still negative. Since we're doing a
+ # zero-padded shift (unsigned), clear the leftmost bit
+ # For positive numbers, this has no side effects
lines.append(self.asm.binary_op("AND", reg_first, "%10"))
- # shift it by one
- lines.append(self.asm.binary_op("DIV", reg_first, 1))
- # make it positive if not already
+ # shift it by one to the right
+ lines.append(self.asm.binary_op("DIV", reg_first, 2))
+ # clear the leftmost bit by masking it with 011..11
mask = "%0" + (self.WORDSIZE - 1) * "1"
- lines.append(self.asm.binary_op("AND", reg_first, mask,
- label=lbl_make_positive))
+ lines.append(self.asm.binary_op("AND", reg_first, mask))
# decrease shift count and finish if nothing to shift
operand /= 2
if operand > 1:
+ # process the remaining shift
lines.append(self.asm.binary_op("DIV", reg_first, operand))
else:
lbl_gen = self.uniqLbl("gen2_loop")
@@ -747,14 +754,12 @@ class Parse(object):
if op == "<<":
lines.append(self.asm.binary_op("MULS", reg_first, 2, label=lbl_gen))
else:
- # now first check if the first number is negative...
- lines.append(self.asm.binary_op("CMP", reg_first, 0))
- lines.append(self.asm.branch_op("BPL", lbl_gen))
- # shift it by one
- lines.append(self.asm.binary_op("DIV", reg_first, 1))
- # make negative values positive
+ # see above big block of comments for explanation
+ lines.append(self.asm.binary_op("AND", reg_first, "%10"))
+ lines.append(self.asm.binary_op("DIV", reg_first, 2))
mask = "%0" + (self.WORDSIZE - 1) * "1"
lines.append(self.asm.binary_op("AND", reg_first, mask))
+
# decrease shift count and finish if shift count is zero
lines.append(self.asm.binary_op("SUB", reg_second, 1))
lines.append(self.asm.branch_op("BEQ", lbl_gen_end))
@@ -1162,6 +1167,23 @@ class Parse(object):
if node.op == "=":
lines.append(self.asm.binary_op("STOR", result_reg,
"[" + lvalue_reg + "]"))
+ elif (len(node.op) == 2 and node.op[1] == "=" and
+ node.op[0] in self.math_ops):
+ binop = self.math_ops[node.op[0]]
+ # abuse lvalue_reg to save a register by storing the value of the
+ # lvalue. This should allow for doing x / y first before assigning
+ # (writing) to y
+ lines.append(self.asm.push(lvalue_reg))
+ # get the value of lvalue, e.g. the value of x
+ lines.append(self.asm.binary_op("LOAD", lvalue_reg, "["+lvalue_reg+"]"))
+ # perform the operation on the value
+ lines.append(self.asm.binary_op(binop, lvalue_reg, result_reg))
+ # since lvalue_reg is now the integer result, use result_reg as the
+ # register for holding the address of y
+ lines.append(self.asm.pull(result_reg))
+ # finally store the result from lvalue_reg into result_reg
+ lines.append(self.asm.binary_op("STOR", lvalue_reg,
+ "[" + result_reg + "]"))
else:
raise RuntimeError("Unsupported assignment operator: " + node.op)
return lines