/*
* AVRgenVisitor.java
*
* AST visitor that generates AVR code.
* Output is written to the PrintWriter passed to constructor.
* Generated AVR code can be run in MJSIM simulator and built
* to run on Meggy Jr device.
*
* WB: +,- extended with INTxBYTE->INT and BYTExINT->INT
* == extended with INTxBYTE->BOOL and BYTExINT->BOOL
*/
package ast_visitors;
import java.io.File;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;
import label.Label;
import ast.visitor.DepthFirstVisitor;
import ast.node.*;
import exceptions.InternalException;
import symtable.*;
public class AVRgenVisitor extends DepthFirstVisitor {
private final PrintWriter out;
private final SymTable mCurrentST;
// Information about the current class
private int class_offset = 0;
private ClassSTE mCurrentClass;
private Object[] mRegList;
// Generate the head of the AVR code file
public AVRgenVisitor(PrintWriter out, SymTable symTable) {
if(out==null) {
throw new InternalException("unexpected null argument");
}
this.out = out;
this.mCurrentST = symTable;
this.out.println( fileToString("avrH.rtl.s") );
}
//========================= Overriding the visitor interface
public void defaultOut(Node node) {
System.err.println("Node not implemented in AVRgenVisitor, " + node.getClass());
}
public void inProgram(Program node) {
}
public void outProgram(Program node) {
out.flush();
}
public void inMainClass(MainClass node) {
}
public void inTopClassDecl(TopClassDecl node) {
mCurrentClass = (ClassSTE) mCurrentST.lookup(node.getName());
mCurrentST.pushScope(node.getName());
}
public void outTopClassDecl(TopClassDecl node) {
mCurrentST.popScope();
Type classType = Type.getClassType(node.getName());
classType.setClassSize(this.class_offset);
this.class_offset = 0;
}
public void outBlockStatement(BlockStatement node) {
}
public void outMainClass(MainClass node) {
this.out.println( fileToString("avrF.rtl.s") );
}
public void outIntegerExp(IntLiteral node) {
this.out.println("");
this.out.println(" # Load constant int " + Integer.toString(node.getIntValue()) );
this.out.println(" ldi r24,lo8("+ Integer.toString(node.getIntValue()) + ")");
this.out.println(" ldi r25,hi8("+ Integer.toString(node.getIntValue()) + ")");
genExpStore(node, new Reg16("r24", "r25"));
}
public void outByteCast(ByteCast node) {
/* if(mCurrentST.getExpType(node.getExp()) == Type.INT ) {
if( (mCurrentST.getExpReg(node.getExp()) == null) || (mCurrentST.getExpReg(node.getExp()) != mCurrentST.getExpReg(node)) ) {
if(mCurrentST.getExpReg(node) != null) {
throw new InternalException("Unexpected register Allocated");
}
*/
this.out.println("");
this.out.println(" # Casting int to byte by popping");
this.out.println(" # 2 bytes off stack and only pushing low order bits");
this.out.println(" # back on. Low order bits are on top of stack.");
this.out.println(" pop r24");
this.out.println(" pop r25");
this.out.println(" push r24");
/*j
}
}
*/
}
public void outColorExp(ColorLiteral node) {
this.out.println("");
this.out.println(" # Color expression " + node.getLexeme());
this.out.println(" ldi r22," + node.getIntValue());
genExpStore(node, new Reg16("r22", null));
}
public void outIdLiteral(IdLiteral node) {
VarSTE varEntry = (VarSTE)mCurrentST.lookup(node.getLexeme());
this.out.println();
this.out.println(" # IdExp");
this.out.println(" # load value for variable " + node.getLexeme() );
if (varEntry.isMember()) {
genLoadThis();
this.out.println(" # variable is a member variable");
} else {
this.out.println(" # variable is a local or param variable");
}
this.out.println();
genExpStore(node, genVarLoad(varEntry, 24));
}
public void outToneExp(ToneLiteral node) {
this.out.println("");
this.out.println("# Push Meggy.Tone." + node.getLexeme() + " onto the stack.");
this.out.println("ldi r25, hi8(" + node.getIntValue() + ")");
this.out.println("ldi r24, lo8(" + node.getIntValue() + ")");
genExpStore(node, new Reg16("r24", "r25"));
}
public void outToneType(ToneType node)
{
}
public void outMeggySetAuxLEDs(MeggySetAuxLEDs node)
{
this.out.println();
this.out.println(" ### Meggy.setAuxLEDs(num) call");
genMoveReg(new Reg16("r24", "r25"), genExpLoad(node.getExp(), 24));
this.out.println(" call _Z10SetAuxLEDsh");
}
public void outMeggySetPixel(MeggySetPixel node)
{
this.out.println("");
this.out.println(" ### Meggy.setPixel(x,y,color) call");
Reg16 reg1 = genExpLoad(node.getColor(), 20);
genMoveReg(new Reg16("r20", null), reg1);
reg1 = genExpLoad(node.getYExp(), 22);
genMoveReg(new Reg16("r22", null), reg1);
reg1 = genExpLoad(node.getXExp(), 24);
genMoveReg(new Reg16("r24", null), reg1);
this.out.println(" call _Z6DrawPxhhh");
this.out.println(" call _Z12DisplaySlatev");
}
public void outTrueExp(TrueLiteral node)
{
this.out.println(" # True/1 expression");
this.out.println(" ldi r22, 1");
genExpStore(node, new Reg16("r22", null));
}
public void outFalseExp(FalseLiteral node)
{
this.out.println(" # False/0 expression");
this.out.println(" ldi r24, 0");
genExpStore(node, new Reg16("r24", null));
}
public void outButtonExp(ButtonLiteral node)
{
}
public void outMeggyDelay(MeggyDelay node)
{
//this.out.println("outMeggyDelay");
this.out.println("");
this.out.println(" ### Meggy.delay() call");
this.out.println(" # load delay parameter");
genMoveReg(new Reg16("r24", "r25"), genExpLoad(node.getExp(), 24));
this.out.println(" call _Z8delay_msj");
}
public void outMeggyToneStart(MeggyToneStart node)
{
this.out.println("");
this.out.println(" ### Meggy.toneStart(tone, time_ms) call");
Reg16 reg1 = genExpLoad(node.getDurationExp(), 22);
genMoveReg(new Reg16("r22", "r23"), reg1);
reg1 = genExpLoad(node.getToneExp(), 24);
genMoveReg(new Reg16("r24", "r25"), reg1);
this.out.println(" call _Z10Tone_Startjj");
}
public void outMeggyCheckButton(MeggyCheckButton node)
{
//this.out.println("# in Meggycheck");
this.out.println("");
this.out.println(" ### MeggyCheckButton");
this.out.println(" call _Z16CheckButtonsDownv");
ButtonLiteral btn = (ButtonLiteral) node.getExp();
String str = btn.getLexeme();
if (str.equals("Meggy.Button.B"))
this.out.println(" lds r24, Button_B");
else if (str.equals("Meggy.Button.A"))
this.out.println(" lds r24, Button_A");
else if (str.equals("Meggy.Button.Up"))
this.out.println(" lds r24, Button_Up");
else if (str.equals("Meggy.Button.Down"))
this.out.println(" lds r24, Button_Down");
else if (str.equals("Meggy.Button.Left"))
this.out.println(" lds r24, Button_Left");
else if (str.equals("Meggy.Button.Right"))
this.out.println(" lds r24, Button_Right");
Label l1 = new Label();
Label l2 = new Label();
Label l3 = new Label();
this.out.println(" # if button value is zero, push 0 else push 1");
this.out.println(" tst r24");
this.out.println(" breq " + l1.toString());
this.out.println(l2.toString() + ":");
this.out.println(" ldi r24, 1");
this.out.println(" jmp " + l3.toString());
this.out.println(l1.toString() + ":");
this.out.println(l3.toString() + ":");
genExpStore(node, new Reg16("r24", null));
}
public void outMeggyGetPixel(MeggyGetPixel node)
{
this.out.println("");
this.out.println(" ### Meggy.getPixel(x,y) call");
genMoveReg(new Reg16("r22", null), genExpLoad(node.getYExp(), 22));
genMoveReg(new Reg16("r24", null), genExpLoad(node.getYExp(), 24));
this.out.println(" call _Z6ReadPxhh");
genExpStore(node, new Reg16("r24", null));
}
public void visitIfStatement(IfStatement node)
{
Label l1 = new Label();
Label l2 = new Label();
Label l3 = new Label();
this.out.println("");
this.out.println(" #### if statement");
if(node.getExp() != null)
node.getExp().accept(this);
this.out.println("");
this.out.println(" # load condition and branch if false");
Reg16 reg = genExpLoad(node.getExp(), 24);
this.out.println(" #load zero into reg");
this.out.println(" ldi r25, 0");
this.out.println("");
this.out.println(" #use cp to set SREG");
this.out.println(" cp " + reg.lo8 + ", r25");
this.out.println(" #WANT breq " + l1.toString());
this.out.println(" brne " + l2.toString());
this.out.println(" jmp " + l1.toString());
this.out.println("");
this.out.println(" # then label for if");
this.out.println(l2.toString() + ":");
if(node.getThenStatement() != null)
node.getThenStatement().accept(this);
this.out.println(" jmp " + l3.toString());
this.out.println("");
this.out.println(" # else label for if");
this.out.println(l1.toString() + ":");
if(node.getElseStatement() != null)
node.getElseStatement().accept(this);
this.out.println("");
this.out.println(" # done label for if");
this.out.println(l3.toString() + ":");
}
public void inWhileStatement(WhileStatement node)
{
}
public void outWhileStatement(WhileStatement node)
{
}
public void visitWhileStatement(WhileStatement node)
{
Label l1 = new Label();
Label l2 = new Label();
Label l3 = new Label();
this.out.println("");
this.out.println(" #### while statement");
this.out.println(l1.toString() + ":");
if(node.getExp() != null)
node.getExp().accept(this);
this.out.println("");
this.out.println(" # if not(condition)");
Reg16 reg = genExpLoad(node.getExp(), 24);
this.out.println(" ldi r25,0");
this.out.println(" cp " + reg.lo8 + ", r25");
this.out.println(" # WANT breq " + l3.toString());
this.out.println(" brne " + l2.toString());
this.out.println(" jmp " + l3.toString());
this.out.println("");
this.out.println(" # while loop body");
this.out.println(l2.toString() + ":");
if(node.getStatement() != null)
node.getStatement().accept(this);
this.out.println("");
this.out.println(" # jump to while test");
this.out.println(" jmp " + l1.toString());
this.out.println("");
this.out.println(" # end of while");
this.out.println(l3.toString() + ":");
}
public void outPlusExp(PlusExp node)
{
Reg16 reg1 = genExpLoad(node.getRExp(), 18);
Reg16 reg2 = genExpLoad(node.getLExp(), 24);
if(mCurrentST.getExpType(node.getLExp()) == Type.BYTE)
promoteVal(reg2);
if(mCurrentST.getExpType(node.getRExp()) == Type.BYTE)
promoteVal(reg1);
this.out.println("");
this.out.println(" # Do add operation");
this.out.println(" add " + reg2.lo8 + ", " + reg1.lo8);
this.out.println(" adc " + reg2.hi8 + ", " + reg1.hi8);
genExpStore(node, reg2);
}
public void outMinusExp(MinusExp node)
{
Reg16 reg1 = genExpLoad(node.getRExp(), 18);
Reg16 reg2 = genExpLoad(node.getLExp(), 24);
if(mCurrentST.getExpType(node.getLExp()) == Type.BYTE)
promoteVal(reg2);
if(mCurrentST.getExpType(node.getRExp()) == Type.BYTE)
promoteVal(reg1);
this.out.println("");
this.out.println(" # Do INT sub operation");
this.out.println(" sub " + reg2.lo8 + ", " + reg1.lo8);
this.out.println(" sbc " + reg2.hi8 + ", " + reg1.hi8);
this.out.println(" # push hi order byte first");
genExpStore(node, reg2);
}
public void outNotExp(NotExp node) {
Reg16 reg1 = genExpLoad(node.getExp(), 24);
this.out.println(" ldi r22, 1");
this.out.println(" eor " + reg1.lo8 + ", r22");
genExpStore(node, reg1);
}
public void outMulExp(MulExp node)
{
this.out.println("");
this.out.println(" # MulExp");
Reg16 reg1 = genExpLoad(node.getRExp(), 18);
Reg16 reg2 = genExpLoad(node.getLExp(), 22);
Reg16 reg3 = new Reg16("r24", null);
Reg16 reg4 = new Reg16("r26", null);
genMoveReg(reg3, reg1);
genMoveReg(reg4, reg2);
this.out.println("");
this.out.println(" # Do mul operation on two input bytes");
this.out.println(" muls " + reg3.lo8 + ", " + reg4.lo8);
genExpStore(node, new Reg16("r0", "r1"));
this.out.println(" # clear r0 and r1");
this.out.println(" eor r0,r0");
this.out.println(" eor r1,r1");
}
public void outNegExp(NegExp node) {
Reg16 reg1 = genExpLoad(node.getExp(), 18);
Reg16 reg2 = genExpLoad(node.getExp(), 22);
if(mCurrentST.getExpType(node.getExp()) == Type.INT) {
this.out.println();
this.out.println(" # neg int");
reg1 = genExpLoad(node.getExp(), 24);
reg2 = new Reg16("r22", "r23");
this.out.println(" ldi " + reg2.lo8 + ", 0");
this.out.println(" ldi " + reg2.hi8 + ", 0");
this.out.println(" sub " + reg2.lo8 + ", " + reg1.lo8);
this.out.println(" sbc " + reg2.hi8 + ", " + reg1.hi8);
genExpStore(node, reg2);
}
else if(mCurrentST.getExpType(node.getExp()) == Type.BYTE) {
this.out.println();
this.out.println(" # neg byt");
reg1 = genExpLoad(node.getExp(), 24);
reg2 = new Reg16("r22", "r23");
this.out.println(" ldi " + reg2.lo8 + ", 0");
this.out.println(" ldi " + reg2.hi8 + ", 0");
this.out.println(" sub " + reg2.lo8 + ", " + reg1.lo8);
this.out.println(" sbc " + reg2.hi8 + ", " + reg1.hi8);
genExpStore(node, reg2);
}
}
public void outEqualExp(EqualExp node) {
/*
------------------------
EqualExp, the equality operator ==
Just like in plus, minus, we need to take the mixed type semantics of Java
into account, by promoting a byte (1 register) to an int (register pair),
making sure the int value correctly preserves the sign.
Outequalexp can generate code like the following:
*/
Label l1 = new Label();
Label l2 = new Label();
Label l3 = new Label();
this.out.println("");
this.out.println(" # equality check expression");
Reg16 reg1 = genExpLoad(node.getRExp(), 18);
Reg16 reg2 = genExpLoad(node.getLExp(), 24);
if ((this.mCurrentST.getExpType(node.getLExp()).getAVRTypeSize() == 1) && (this.mCurrentST.getExpType(node.getRExp()).getAVRTypeSize() == 1))
this.out.println(" cp " + reg2.lo8 + ", " + reg1.lo8);
else
{
if (this.mCurrentST.getExpType(node.getLExp()).getAVRTypeSize() == 1) {
promoteVal(reg2);
}
if (this.mCurrentST.getExpType(node.getRExp()).getAVRTypeSize() == 1) {
promoteVal(reg1);
}
this.out.println(" cp " + reg2.lo8 + ", " + reg1.lo8);
this.out.println(" cpc " + reg2.hi8 + ", " + reg1.hi8);
}
this.out.println(" breq " + l2.toString());
// result is false
this.out.println();
this.out.println(" # result is false");
this.out.println(l1.toString() + ":");
this.out.println(" ldi r24, 0");
this.out.println(" jmp " + l3);
this.out.println();
this.out.println(" # result is true");
this.out.println(l2 + ":");
this.out.println(" ldi r24, 1");
this.out.println();
this.out.println(" # store result of equal expression");
this.out.println(l3 + ":");
genExpStore(node, new Reg16("r24", null));
}
public void outThisExp(ThisLiteral node) {
this.out.println();
if (mCurrentClass == null) {
throw new InternalException("outThisExp: mCurrentClass==null");
}
genLoadThis();
Reg16 reg1 = new Reg16("r30", "r31");
genExpStore(node, reg1);
}
public void visitAndExp(AndExp node) {
this.out.println("");
this.out.println(" #### short-circuited && operation");
this.out.println(" # &&: left operand");
if(node.getLExp() != null)
node.getLExp().accept(this);
Label l1 = new Label();
Label l2 = new Label();
this.out.println("");
this.out.println(" # &&: if left operand is false do not eval right");
Reg16 reg1 = genExpLoad(node.getLExp(), 24);
genExpStore(node, reg1);
this.out.println(" # compare left exp with zero");
this.out.println(" ldi r25, 0");
this.out.println(" cp " + reg1.lo8 + ", r25");
this.out.println(" # Want this, breq" + l1.toString());
this.out.println(" brne " + l2.toString());
this.out.println(" jmp " + l1.toString());
this.out.println("");
this.out.println(l2.toString() + ":");
this.out.println(" # right operand");
genExpLoad(node.getLExp(), 24);
if(node.getRExp() != null)
node.getRExp().accept(this);
Reg16 reg2 = genExpLoad(node.getLExp(), 24);
genExpStore(node, reg1);
this.out.println("");
this.out.println(l1.toString() + ":");
}
public void outVoidType(VoidType node)
{
}
public void outNewExp(NewExp node)
{
int i = Type.getClassType(node.getId()).getClassSize();
this.out.println();
this.out.println(" # NewExp");
this.out.println(" ldi r24, lo8(" + i + ")");
this.out.println(" ldi r25, hi8(" + i + ")");
this.out.println(" # allocating object of size " + i + " on heap");
this.out.println(" call malloc");
this.out.println(" # push object address");
genExpStore(node, new Reg16("r24", "r25"));
//this.out.flush();
}
public void outCallStatement(CallStatement node)
{
genFunctionCall(node.getExp(), node.getId(), node.getArgs());
}
public void outIntType(IntType paramIntType) {
}
public void outIntArrayType(IntArrayType node) {
}
public void outFormal(Formal node) {
}
public void outVarDecl(VarDecl node) {
}
public void outBoolType(BoolType node) {
}
public void outClassType(ClassType node) {
}
public void outColorType(ColorType node) {
}
public void outColorArrayType(ColorArrayType node) {
}
public void outByteType(ByteType node) {
}
public void outCallExp(CallExp node) {
genFunctionCall(node.getExp(), node.getId(), node.getArgs());
this.out.println();
this.out.println(" # handle return value");
Reg16 reg = new Reg16("r24", "r25");
genExpStore(node, reg);
//this.out.flush();
}
public void outLtExp(LtExp node) {
Label l1 = new Label();
Label l2 = new Label();
Label l3 = new Label();
this.out.println();
this.out.println(" # less than expression");
Reg16 reg1 = genExpLoad(node.getRExp(), 18);
Reg16 reg2 = genExpLoad(node.getLExp(), 24);
if ((mCurrentST.getExpType(node.getLExp()).getAVRTypeSize() == 1) && (mCurrentST.getExpType(node.getRExp()).getAVRTypeSize() == 1)) {
this.out.println(" cp " + reg2.lo8 + ", " + reg1.lo8 );
}
else {
if (mCurrentST.getExpType(node.getLExp()).getAVRTypeSize() == 1) {
promoteVal(reg2);
}
if (mCurrentST.getExpType(node.getRExp()).getAVRTypeSize() == 1) {
promoteVal(reg1);
}
this.out.println(" cp " + reg2.lo8 + ", " + reg1.lo8);
this.out.println(" cpc " + reg2.hi8 + ", " + reg1.hi8);
}
this.out.println(" brlt " + l2);
this.out.println();
this.out.println(" # load false");
this.out.println(l1 + ":");
this.out.println(" ldi r24, 0");
this.out.println(" jmp " + l3);
this.out.println();
this.out.println(" # load true");
this.out.println(l2 + ":");
this.out.println(" ldi r24, 1");
this.out.println();
this.out.println(" # push result of less than");
this.out.println(l3 + ":");
genExpStore(node, new Reg16("r24", null));
}
public void inMethodDecl(MethodDecl node) {
String name = node.getName();
MethodSTE methodEntry = (MethodSTE) mCurrentST.lookup(name);
mCurrentST.pushScope(name);
name = methodEntry.getLong();
this.out.println();
this.out.println(" .text");
this.out.println(".global " + name);
this.out.println(" .type " + name + ", @function");
this.out.println(name + ":");
//this.out.println(" # store off the frame pointer");
this.out.println(" push r29");
this.out.println(" push r28");
//this.out.println(" # store off parameter(s)");
HashSet<Integer> regSet = methodEntry.getUsedReg();
mRegList = regSet.toArray();
Integer ctr = 0;
for (int i = 0; i < mRegList.length; i++) {
ctr = (Integer) mRegList[i];
this.out.println(" push r" + Integer.toString(ctr + 1) );
this.out.println(" push r" + Integer.toString(ctr) );
}
this.out.println(" # make space for locals and params");
this.out.println(" ldi r30, 0");
for (int i = 0; i < methodEntry.getVarNumBytes(); i++) {
this.out.println(" push r30");
}
this.out.println();
this.out.println(" # Copy stack pointer to frame pointer");
this.out.println(" in r28,__SP_L__");
this.out.println(" in r29,__SP_H__");
int i = 24;
LinkedList<VarSTE> paramList = methodEntry.getParamList();
Iterator itr = ((List) paramList).iterator();
this.out.println();
this.out.println(" # save off parameters");
while (itr.hasNext()) {
VarSTE varEntry = (VarSTE) itr.next();
genVarStore(varEntry, new Reg16("r" + Integer.toString(i), "r" + Integer.toString(i + 1)) );
i -= 2;
}
this.out.println("/* done with function "+ name + " prologue */");
this.out.println();
}
public void outMethodDecl(MethodDecl node) {
/*
this.out.println(" #handle return value");
this.out.println(" pop r24");
this.out.println(" #pop parameter off stack");
this.out.println(" pop r18");
this.out.println(" #restore the frame pointer");
this.out.println(" pop r28");
this.out.println(" pop r29");
this.out.println("#return");
this.out.println("ret");
this.out.println(".size methodname, .-methodname");
*/
mCurrentST.popScope();
String name = node.getName();
MethodSTE methodEntry = (MethodSTE) mCurrentST.lookup(name);
this.out.println();
this.out.println("/* epilogue start for " + methodEntry.getLong() + " */");
if (node.getExp() != null) {
this.out.println(" # handle return value");
genMoveReg(new Reg16("r24", "r25"), genExpLoad(node.getExp(), 24));
}
else {
this.out.println(" # no return value");
}
this.out.println(" # pop space off stack for parameters and locals");
for (int i = 0; i < methodEntry.getVarNumBytes(); i++) {
this.out.println(" pop r30");
}
for (int i = mRegList.length - 1; i >= 0; i--) {
Integer regDex = (Integer)mRegList[i];
this.out.println(" pop r" + regDex.toString() );
this.out.println(" pop r" + Integer.toString(regDex.intValue() + 1) );
}
this.out.println(" # restoring the frame pointer");
this.out.println(" pop r28");
this.out.println(" pop r29");
this.out.println(" ret");
this.out.println(" .size " + methodEntry.getLong() + ", .-" + methodEntry.getLong() );
this.out.println();
//this.out.flush();
}
public void outArrayAssignStatement(ArrayAssignStatement node) {
VarSTE varEntry = (VarSTE)this.mCurrentST.lookup(node.getIdLit().getLexeme());
this.out.println();
this.out.println(" ### ArrayAssignStatement");
this.out.println(" # load rhs");
Reg16 reg = genExpLoad(node.getExp(), 24);
if ((mCurrentST.getExpType(node.getExp()) == Type.BYTE) && (varEntry.getType() == Type.INT))
{
promoteVal(reg);
}
genArrayElemAddressArithmetic(varEntry.getType(), node.getIdLit(), node.getIndex());
this.out.println(" # store rhs into memory location for array element");
if (varEntry.getType() == Type.COLOR_ARRAY) {
this.out.println(" std Z+0, " + reg.lo8);
} else if (varEntry.getType() == Type.INT_ARRAY) {
this.out.println(" std Z+0, " + reg.lo8);
this.out.println(" std Z+1, " + reg.hi8);
} else {
throw new InternalException("Unknown array type.");
}
//this.out.flush();
}
public void outAssignStatement(AssignStatement node) {
VarSTE varEntry = (VarSTE)mCurrentST.lookup(node.getId());
this.out.println();
this.out.println(" ### AssignStatement");
this.out.println(" # load rhs exp");
Reg16 reg = genExpLoad(node.getExp(), 24);
if ((mCurrentST.getExpType(node.getExp()) == Type.BYTE) && (varEntry.getType() == Type.INT))
{
promoteVal(reg);
}
if (varEntry.isMember()) {
genLoadThis();
}
this.out.println(" # store rhs into var " + varEntry.getName() );
genVarStore(varEntry, reg);
//this.out.flush();
}
public void outNewArrayExp(NewArrayExp node) {
this.out.println();
this.out.println(" ### NewArrayExp, allocating a new array");
this.out.println(" # loading array size in elements");
Reg16 reg = genExpLoad(node.getExp(), 26);
if (mCurrentST.getExpType(node.getExp()) == Type.BYTE) {
promoteVal(reg);
}
this.out.println(" # since num elems might be in caller-saved registers");
this.out.println(" # need to push num elems onto the stack around call to malloc");
this.out.println(" # if had three-address code reg alloc could work around this");
this.out.println(" push " + reg.hi8 );
this.out.println(" push " + reg.lo8 );
if (mCurrentST.getExpType(node) == Type.INT_ARRAY)
{
this.out.println(" # add size in elems to self to multiply by 2");
this.out.println(" # complements of Jason Mealler");
this.out.println(" add " + reg.lo8 + "," + reg.lo8 );
this.out.println(" adc " + reg.hi8 + "," + reg.hi8 );
}
this.out.println(" # need bytes for elems + 2 in bytes");
this.out.println(" ldi r24, 2");
this.out.println(" ldi r25, 0");
this.out.println(" add r24," + reg.lo8);
this.out.println(" adc r25," + reg.hi8);
this.out.println(" # call malloc, it expects r25:r24 as input");
this.out.println(" call malloc");
this.out.println(" # set .length field to number of elements");
this.out.println(" mov r31, r25");
this.out.println(" mov r30, r24");
this.out.println(" pop " + reg.lo8);
this.out.println(" pop " + reg.hi8);
this.out.println(" std Z+0," + reg.lo8);
this.out.println(" std Z+1," + reg.hi8);
this.out.println(" # store object address");
genExpStore(node, new Reg16("r30", "r31"));
//this.out.flush();
}
public void outArrayExp(ArrayExp node) {
this.out.println();
this.out.println(" ### ArrayExp");
genArrayElemAddressArithmetic(mCurrentST.getExpType(node.getExp()), node.getExp(), node.getIndex());
this.out.println(" # load array element and push onto stack");
Reg16 reg = new Reg16("r24", "r25");
if (mCurrentST.getExpType(node.getExp()) == Type.COLOR_ARRAY) {
this.out.println(" ldd " + reg.lo8 + ", Z+0");
} else if (mCurrentST.getExpType(node.getExp()) == Type.INT_ARRAY) {
this.out.println(" ldd " + reg.lo8 + ", Z+0");
this.out.println(" ldd " + reg.hi8 + ", Z+1");
} else {
throw new InternalException("Unknown array type, " + mCurrentST.getExpType(node).toString());
}
genExpStore(node, reg);
//this.out.flush();
}
private void genArrayElemAddressArithmetic(Type type, Node expNode, Node indexNode) {
this.out.println(" # calculate the array element address by first");
this.out.println(" # loading index");
Reg16 reg1 = genExpLoad(indexNode, 18);
if (this.mCurrentST.getExpType(indexNode) == Type.BYTE) {
promoteVal(reg1);
}
if (type == Type.INT_ARRAY)
{
this.out.println(" # add size in elems to self to multiply by 2");
this.out.println(" # complements of Jason Mealler");
this.out.println(" add " + reg1.lo8 + "," + reg1.lo8);
this.out.println(" adc " + reg1.hi8 + "," + reg1.hi8);
}
this.out.println(" # put index*(elem size in bytes) into r31:r30");
this.out.println(" mov r31, " + reg1.hi8);
this.out.println(" mov r30, " + reg1.lo8);
this.out.println(" # want result of addressing arithmetic ");
this.out.println(" # to be in r31:r30 for access through Z");
this.out.println(" # index over length");
this.out.println(" ldi r20, 2");
this.out.println(" ldi r21, 0");
this.out.println(" add r30, r20");
this.out.println(" adc r31, r21");
this.out.println(" # loading array reference");
Reg16 reg2 = genExpLoad(expNode, 22);
this.out.println(" # add array reference to result of indexing arithmetic");
this.out.println(" add r30, " + reg2.lo8);
this.out.println(" adc r31, " + reg2.hi8);
}
public void outLengthExp(LengthExp node)
{
this.out.println();
this.out.println(" # length of array");
Reg16 reg = genExpLoad(node.getExp(), 30);
genMoveReg(new Reg16("r30", "r31"), reg);
this.out.println(" ldd r24, Z+0");
this.out.println(" ldd r25, Z+1");
genExpStore(node, new Reg16("r24", "r25"));
}
//========================= Register Functions
private Reg16 getExpReg(Node node) {
Reg16 reg = null;
Integer regInt = mCurrentST.getExpReg(node);
if(regInt != null) {
int i = regInt.intValue() + 1;
reg = new Reg16("r" + Integer.toString(regInt), "r" + Integer.toString(i));
}
return reg;
}
private Reg16 getVarReg(VarSTE node) {
Reg16 reg = null;
Integer regInt = Integer.valueOf(node.getReg());
if(regInt > 0) {
if(node.getType().getAVRTypeSize() == 2)
reg = new Reg16("r" + Integer.toString(regInt), "r" + Integer.toString(regInt));
else
reg = new Reg16("r" + Integer.toString(regInt), "r" + Integer.toString(regInt));
}
return reg;
}
public Reg16 genExpLoad(Node node, int i) {
Reg16 reg = getExpReg(node);
if(reg == null) {
reg = new Reg16("r" + Integer.toString(i), "r" + Integer.toString(i+1) );
if(mCurrentST.getExpType(node).getAVRTypeSize() == 2) {
this.out.println(" # load a two byte expression off stack");
this.out.println(" pop " + reg.lo8);
this.out.println(" pop " + reg.hi8);
}
else {
this.out.println(" # load a one byte expression off stack");
this.out.println(" pop " + reg.lo8);
}
}
return reg;
}
public void genExpStore(Node node, Reg16 regPair) {
Reg16 reg = getExpReg(node);
if(reg == null) {
if(mCurrentST.getExpType(node).getAVRTypeSize() == 2) {
this.out.println(" # push two byte expression onto stack");
this.out.println(" push " + regPair.hi8);
this.out.println(" push " + regPair.lo8);
}
else {
this.out.println(" # push one byte expression onto stack");
this.out.println(" push " + regPair.lo8);
}
}
else if (!(reg.lo8.equals(regPair.lo8)))
genMoveReg(reg, regPair);
}
private Reg16 genVarLoad(VarSTE node, int i) {
Reg16 reg = getVarReg(node);
if(reg == null) {
reg = new Reg16("r" + Integer.toString(i), "r" + Integer.toString(i+1) );
if(node.getType().getAVRTypeSize() == 2) {
this.out.println(" # load a two byte variable from base+offset");
this.out.println(" ldd " + reg.hi8 + ", " + node.getBase() + " + " + Integer.toString(node.getOffset() + 1) );
this.out.println(" ldd " + reg.lo8 + ", " + node.getBase() + " + " + Integer.toString(node.getOffset()) );
}
else {
this.out.println(" # load a one byte variable from base+offset");
this.out.println(" ldd " + reg.lo8 + ", " + node.getBase() + " + " + Integer.toString(node.getOffset()) );
}
}
else
this.out.println(" # var " + node.getName() + " is in " + reg.lo8);
return reg;
}
public void genVarStore(VarSTE node, Reg16 regPair) {
Reg16 reg = getVarReg(node);
if(reg != null) {
genMoveReg(reg, regPair);
}
else if (node.getType().getAVRTypeSize() == 1) {
this.out.println(" std " + node.getBase() + " + " + Integer.toString(node.getOffset()) + ", " + regPair.lo8 );
}
else if (node.getType().getAVRTypeSize() == 2) {
this.out.println(" std " + node.getBase() + " + " + Integer.toString(node.getOffset() + 1) + ", " + regPair.hi8 );
this.out.println(" std " + node.getBase() + " + " + Integer.toString(node.getOffset()) + ", " + regPair.lo8 );
}
}
private void genMoveReg(Reg16 reg1, Reg16 reg2) {
if (!reg1.lo8.equals(reg2.lo8)) {
this.out.println(" # move low byte src into dest reg");
this.out.println(" mov " + reg1.lo8 + ", " + reg2.lo8);
}
if((reg1.hi8 != null) && (reg2.hi8 != null) && (!reg1.lo8.equals(reg2.lo8)) ) {
this.out.println(" # move hi byte src into dest reg");
this.out.println(" mov " + reg1.hi8 + ", " + reg2.hi8);
}
}
private void genLoadThis() {
Reg16 reg1 = new Reg16("r30", "r31");
this.out.println();
this.out.println(" # loading the implicit \"this\"");
this.out.println();
VarSTE varEntry = (VarSTE) mCurrentST.lookup("this");
Reg16 reg2 = genVarLoad(varEntry, 30);
genMoveReg(reg1, reg2);
}
private class Reg16 {
public String lo8;
public String hi8;
public Reg16(String lo, String hi) {
lo8 = lo;
hi8 = hi;
}
}
private Type genFunctionCall(IExp iExp, String name, LinkedList<IExp> args) {
Type expType = mCurrentST.getExpType(iExp);
ClassSTE classSTE = mCurrentST.lookupClass(expType.getName());
MethodSTE methodSTE = (MethodSTE)classSTE.getScope().lookup(name);
MethodSignature sig = methodSTE.getSignature();
this.out.println();
this.out.println(" #### function call");
Object params = new ArrayList(args);
this.out.println(" # put parameter values into appropriate registers");
for (int i = ((ArrayList)params).size(); i > 0; i--) {
IExp iexpCur = (IExp)((ArrayList)params).get(i - 1);
Reg16 reg1 = genExpLoad(iexpCur, 24 - 2 * i);
Type curType = mCurrentST.getExpType(iexpCur);
Type cursigType = sig.getArg(i - 1);
if ((curType == Type.BYTE) && (cursigType == Type.INT))
promoteVal(reg1);
Reg16 reg2;
if (cursigType.getAVRTypeSize() == 2)
reg2 = new Reg16("r" + Integer.toString(24 - 2 * i), "r" + Integer.toString(24 - 2 * i + 1));
else {
reg2 = new Reg16("r" + Integer.toString(24 - 2 * i), null);
}
genMoveReg(reg2, reg1);
}
this.out.println(" # receiver will be passed as first param");
params = genExpLoad(iExp, 24);
Reg16 reg3 = new Reg16("r24", "r25");
genMoveReg(reg3, (Reg16)params);
this.out.println();
this.out.println(" call " + methodSTE.getLong() );
return methodSTE.getSignature().getReturnType();
}
private String fileToString(String filename) {
InputStream iStream=null;
BufferedReader bufReader=null;
String output = "";
try {
iStream = this.getClass().getClassLoader().getResourceAsStream(filename);
bufReader = new BufferedReader(new InputStreamReader(iStream));
String line = null;
while ( (line = bufReader.readLine()) != null)
output += line + "\n";
}
catch (Exception e) {
e.printStackTrace();
}
finally{
try{
if(iStream!=null)
iStream.close();
if(bufReader!=null)
bufReader.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
return output;
}
public void promoteVal(Reg16 regPair) {
Label l1 = new Label();
Label l2 = new Label();
this.out.println(" # promoting a byte to an int");
this.out.println(" tst " + regPair.lo8);
this.out.println(" brlt " + l1.toString());
this.out.println(" ldi r25, 0");
this.out.println(" jmp " + l2.toString());
this.out.println(l1.toString() + ":");
this.out.println(" ldi r25, hi8(-1)");
this.out.println(l2.toString() + ":");
genMoveReg(regPair, new Reg16(regPair.lo8, "r25"));
}
}