Beispiel #1
0
  // Sets the registers with the alu's output according to
  // the given instruction
  // Throws ProgramException if destination contains M and A contains
  // an illegal address.
  protected void setDestination(short instruction) throws ProgramException {
    boolean destA = (instruction & 0x0020) > 0;
    boolean destD = (instruction & 0x0010) > 0;
    boolean destM = (instruction & 0x0008) > 0;

    if (destM) {
      int address = A.get();
      if ((address < 0) || (address >= M.getSize())) {
        throw new ProgramException(
            "At line "
                + PC.get()
                + ": Destination is M but A="
                + address
                + " is an illegal memory address.");
      }
      A.setUpdatePointer(true);
      bus.send(alu, 2, M, address);
      A.setUpdatePointer(false);
    }
    if (destA) {
      bus.send(alu, 2, A, 0);
    }
    if (destD) {
      bus.send(alu, 2, D, 0);
    }
  }
  // sends a value from the appropriate stack (at sp-1) to the ram at the given index
  // and increments sp.
  private void popToRAM(int stackID, int index) throws ProgramException {
    short newSP = (short) (getSP() - 1);
    bus.send((stackID == MAIN_STACK ? stackSegment : workingStackSegment), newSP, ram, index);

    checkSP(newSP);
    setSP(newSP);
  }
  // Push a value from the calculator at the given index into the appropriate stack.
  private void pushFromCalculator(int stackID, int index) throws ProgramException {
    short sp = getSP();
    bus.send(calculator, index, (stackID == MAIN_STACK ? stackSegment : workingStackSegment), sp);

    checkSP((short) (sp + 1));
    setSP((short) (sp + 1));
  }
  // sends a value from the appropriate stack (at sp-1) to the given segment at the given index
  // and increments sp.
  private void popToSegment(int stackID, short segmentCode, int index) throws ProgramException {
    short newSP = (short) (getSP() - 1);
    MemorySegment segment =
        (segmentCode == HVMInstructionSet.STATIC_SEGMENT_CODE)
            ? staticSegment
            : segments[segmentCode];

    checkSegmentIndex(segment, segmentCode, index);
    bus.send((stackID == MAIN_STACK ? stackSegment : workingStackSegment), newSP, segment, index);

    checkSP(newSP);
    setSP(newSP);
  }
  // sends a value from the given segment at the the given index to the appropriate stack (at sp)
  // and increments sp.
  private void pushFromSegment(int stackID, short segmentCode, int index) throws ProgramException {
    short sp = getSP();
    MemorySegment segment =
        (segmentCode == HVMInstructionSet.STATIC_SEGMENT_CODE)
            ? staticSegment
            : segments[segmentCode];

    checkSegmentIndex(segment, segmentCode, index);
    bus.send(segment, index, (stackID == MAIN_STACK ? stackSegment : workingStackSegment), sp);

    checkSP((short) (sp + 1));
    setSP((short) (sp + 1));
  }
Beispiel #6
0
  // computes the exp part of the given instruction.
  // The result will be at the alu's output.
  // Throws ProgramException if the calculation involves M and A contains
  // an illegal address.
  protected void computeExp(short instruction) throws ProgramException {
    boolean indirect = (instruction & 0x1000) > 0;
    boolean zd = (instruction & 0x0800) > 0;
    boolean nd = (instruction & 0x0400) > 0;
    boolean zm = (instruction & 0x0200) > 0;
    boolean nm = (instruction & 0x0100) > 0;
    boolean f = (instruction & 0x0080) > 0;
    boolean no = (instruction & 0x0040) > 0;

    try {
      alu.setCommand(
          assemblerTranslator.getExpByCode((short) (instruction & 0xffc0)), zd, nd, zm, nm, f, no);
    } catch (AssemblerException ae) {
    }

    bus.send(D, 0, alu, 0); // sends D to input0 of the alu

    // sends A or M[A] to input1 of the alu
    if (indirect) {
      int address = A.get();
      if ((address < 0) || (address >= M.getSize())) {
        throw new ProgramException(
            "At line "
                + PC.get()
                + ": Expression involves M but A="
                + address
                + " is an illegal memory address.");
      }
      A.setUpdatePointer(true);
      bus.send(M, address, alu, 1);
      A.setUpdatePointer(false);
    } else {
      bus.send(A, 0, alu, 1);
    }

    alu.compute();
  }
Beispiel #7
0
  // Sets the program counter (if necessary) according to
  // the given instruction and the alu's output.
  // If the program counter was changed, returns true, otherwise false.
  // Throws ProgramException if the program counter should be changed and A
  // contains an illegal address.
  protected boolean checkJump(short instruction) throws ProgramException {
    boolean jumpNegative = (instruction & 0x0004) > 0;
    boolean jumpEqual = (instruction & 0x0002) > 0;
    boolean jumpPositive = (instruction & 0x0001) > 0;
    boolean changed = false;

    short exp = alu.getValueAt(2);

    if (((exp < 0) && jumpNegative) || ((exp == 0) && jumpEqual) || ((exp > 0) && jumpPositive)) {
      int newPC = A.get();
      if ((newPC < 0) || (newPC >= Definitions.ROM_SIZE)) {
        throw new ProgramException(
            "At line "
                + PC.get()
                + ": Jump requested but A="
                + newPC
                + " is an illegal program address.");
      }
      bus.send(A, 0, PC, 0);
      changed = true;
    }

    return changed;
  }
Beispiel #8
0
  /**
   * Executes the current instruction (ROM at pc). Throws ProgramException if the current
   * instruction is illegal or if it causes an illegal effect (read/write from M when A is an
   * illegal address or jump when A is an illegal address).
   */
  public void executeInstruction() throws ProgramException {
    short instruction = rom.getValueAt(PC.get());
    boolean pcChanged = false;

    if ((instruction & 0x8000) == 0) {
      bus.send(rom, PC.get(), A, 0);
    } else if ((instruction & 0xe000) == 0xe000) {
      computeExp(instruction);
      setDestination(instruction);
      pcChanged = checkJump(instruction);
    } else if (instruction != HackAssemblerTranslator.NOP) {
      throw new ProgramException("At line " + PC.get() + ": Illegal instruction");
    }

    if (!pcChanged) {
      short newPC = (short) (PC.get() + 1);
      if ((newPC < 0) || (newPC >= Definitions.ROM_SIZE)) {
        throw new ProgramException("At line " + PC.get() + ": Can't continue past last line");
      }
      PC.setValueAt(0, newPC, true);
    }

    time++;
  }
  /** Returns the value of the function to the top of the stack. */
  public void returnFromFunction() throws ProgramException {

    // make sure that there's somewhere to return to (old local <> 0)
    if (stackSegment.getValueAt(Definitions.LOCAL_POINTER_ADDRESS) == 0)
      throw new ProgramException(
          "Nowhere to return to in "
              + getCallStack().getTopFunction()
              + "."
              + getCurrentInstruction().getIndexInFunction());

    // done in order to clear the method stack's contents
    workingStackSegment.setStartAddress(getSP());

    bus.send(ram, Definitions.LOCAL_POINTER_ADDRESS, ram, Definitions.R13_ADDRESS); // R13 = lcl
    bus.send(
        stackSegment,
        stackSegment.getValueAt(Definitions.LOCAL_POINTER_ADDRESS) - 5,
        ram,
        Definitions.R14_ADDRESS); // R14 = return address
    bus.send(
        stackSegment,
        getSP() - 1,
        stackSegment,
        ram.getValueAt(Definitions.ARG_POINTER_ADDRESS)); // *arg = return value
    setSP((short) (ram.getValueAt(Definitions.ARG_POINTER_ADDRESS) + 1)); // SP = arg + 1
    bus.send(
        stackSegment,
        ram.getValueAt(Definitions.R13_ADDRESS) - 1,
        ram,
        Definitions.THAT_POINTER_ADDRESS); // that = *(R13 - 1)
    bus.send(
        stackSegment,
        ram.getValueAt(Definitions.R13_ADDRESS) - 2,
        ram,
        Definitions.THIS_POINTER_ADDRESS); // this = *(R13 - 2)
    bus.send(
        stackSegment,
        ram.getValueAt(Definitions.R13_ADDRESS) - 3,
        ram,
        Definitions.ARG_POINTER_ADDRESS); // arg = *(R13 - 3)
    bus.send(
        stackSegment,
        ram.getValueAt(Definitions.R13_ADDRESS) - 4,
        ram,
        Definitions.LOCAL_POINTER_ADDRESS); // lcl = *(R13 - 4)

    // removes the top function from the call stack
    callStack.popFunction();

    // check whether there is a "calling frame"
    if (stackFrames.size() > 0) {
      // retrieve stack frame address of old function
      int frameAddress = ((Integer) stackFrames.lastElement()).intValue();
      stackFrames.removeElementAt(stackFrames.size() - 1);
      workingStackSegment.setStartAddress(frameAddress);

      // disable non relevant range of the local segment - enable only the locals
      // of the function that we returned to.
      localSegment.setEnabledRange(
          Math.max(localSegment.getStartAddress(), Definitions.STACK_START_ADDRESS),
          frameAddress - 1,
          true);

      // enable in the arg segment only the number of args that were sent to the function
      // that we returned to.
      argSegment.setEnabledRange(
          argSegment.getStartAddress(), localSegment.getStartAddress() - 6, true);

      // enable this, that according to their retrieved pointers
      thisSegment.setEnabledRange(
          Math.max(thisSegment.getStartAddress(), Definitions.HEAP_START_ADDRESS),
          Definitions.HEAP_END_ADDRESS,
          true);
      thatSegment.setEnabledRange(
          Math.max(thatSegment.getStartAddress(), Definitions.HEAP_START_ADDRESS),
          Definitions.SCREEN_END_ADDRESS,
          true);
    } /* else {
      	error("Nowhere to return to");
      } */
    // Allow return if we previously had "function" even with no call -
    // For the SimpleFunction test

    short returnAddress = ram.getValueAt(Definitions.R14_ADDRESS);
    if (returnAddress == VMProgram.BUILTIN_FUNCTION_ADDRESS) {
      staticSegment.setEnabledRange(0, -1, true); // empty static segment
      builtInFunctionsRunner.returnToBuiltInFunction(popValue(METHOD_STACK));
    } else if (returnAddress >= 0 && returnAddress < program.getSize()) {
      // sets the static segment range
      if (stackFrames.size() > 0) {
        setStaticRange(callStack.getTopFunction());
      } else {
        staticSegment.setStartAddress(Definitions.VAR_START_ADDRESS);
        staticSegment.setEnabledRange(
            Definitions.VAR_START_ADDRESS, Definitions.VAR_END_ADDRESS - 1, true);
      }
      program.setPC((short) (returnAddress - 1)); // set previousPC correctly
      program.setPC(returnAddress); // pc = *sp
    } else {
      error("Illegal return address");
    }
  }