Package ast_visitors

Source Code of ast_visitors.AVRgenVisitor$Reg16

/*
* 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"));

  }

}
TOP

Related Classes of ast_visitors.AVRgenVisitor$Reg16

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.