Download | Plain Text | Line Numbers


/**
 * @module instructions
 * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348)
 * @brief  Implementations of CInstruction
 * @date   26.05.2009
 */
 
#ifndef INSTRUCTIONS_H
#define INSTRUCTIONS_H 1
 
#include "cinstruction.h"
#include "ccpu.h"
#include "cprogram.h"
 
/**
 * @class CInstructionInc
 *
 * Implementation of assembler command "inc"
 * Syntax: inc R1
 *   (R1++)
 */
template <class T>
class CInstructionInc
  : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionInc()
      : CInstruction<T>("inc")
    {}
 
    CInstructionInc *factory()
    {
      return new CInstructionInc;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionInc<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 1)
    throw CInstructionError("Invalid paramater count - must be 1");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionInc<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  cpu->getRegisters()[ m_regidx1 ]++;
}
 
/*============================================================================*/
 
/**
 * @class CInstructionDec
 *
 * Implementation of assembler command "dec"
 * Syntax: dec R1
 *   (R1--)
 */
template <class T>
class CInstructionDec
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionDec()
      : CInstruction<T>("dec")
    {}
 
    CInstructionDec *factory()
    {
      return new CInstructionDec;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionDec<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 1)
    throw CInstructionError("Invalid paramater count - must be 1");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionDec<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  cpu->getRegisters()[ m_regidx1 ]--;
}
 
/*============================================================================*/
 
/**
 * @class CInstructionAdd
 *
 * Implementation of assembler command "add"
 * Syntax: add R1, R2, R3
 *   (R1 = R2 + R3)
 */
template <class T>
class CInstructionAdd
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionAdd()
      : CInstruction<T>("add")
    {}
 
    CInstructionAdd *factory()
    {
      return new CInstructionAdd;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** register number */
    unsigned m_regidx2;
    /** register number */
    unsigned m_regidx3;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionAdd<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 3)
    throw CInstructionError("Invalid paramater count - must be 3");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx2 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx3 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionAdd<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  super::checkRegister(cpu, m_regidx2);
  super::checkRegister(cpu, m_regidx3);
  cpu->getRegisters()[ m_regidx1 ] = cpu->getRegisters()[ m_regidx2 ]
    + cpu->getRegisters()[ m_regidx3 ];
}
 
/*============================================================================*/
 
/**
 * @class CInstructionSub
 *
 * Implementation of assembler command "sub"
 * Syntax: sub R1, R2, R3
 *   (R1 = R2 - R3)
 */
template <class T>
class CInstructionSub
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionSub()
      : CInstruction<T>("sub")
    {}
 
    CInstructionSub *factory()
    {
      return new CInstructionSub;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** register number */
    unsigned m_regidx2;
    /** register number */
    unsigned m_regidx3;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionSub<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 3)
    throw CInstructionError("Invalid paramater count - must be 3");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx2 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx3 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionSub<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  super::checkRegister(cpu, m_regidx2);
  super::checkRegister(cpu, m_regidx3);
  cpu->getRegisters()[ m_regidx1 ] = cpu->getRegisters()[ m_regidx2 ]
    - cpu->getRegisters()[ m_regidx3 ];
}
 
/*============================================================================*/
 
/**
 * @class CInstructionMul
 *
 * Implementation of assembler command "mul"
 * Syntax: mul R1, R2, R3
 *   (R1 = R2 * R3)
 */
template <class T>
class CInstructionMul
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionMul()
      : CInstruction<T>("mul")
    {}
 
    CInstructionMul *factory()
    {
      return new CInstructionMul;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** register number */
    unsigned m_regidx2;
    /** register number */
    unsigned m_regidx3;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionMul<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 3)
    throw CInstructionError("Invalid paramater count - must be 3");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx2 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx3 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionMul<T>::execute(CCPU<T> *cpu)
{
  super::checkRegister(cpu, m_regidx1);
  super::checkRegister(cpu, m_regidx2);
  super::checkRegister(cpu, m_regidx3);
  cpu->getRegisters()[ m_regidx1 ] = cpu->getRegisters()[ m_regidx2 ]
    * cpu->getRegisters()[ m_regidx3 ];
}
 
/*============================================================================*/
 
/**
 * @class CInstructionDiv
 *
 * Implementation of assembler command "div"
 * Syntax: div R1, R2, R3
 *   (R1 = R2 / R3)
 */
template <class T>
class CInstructionDiv
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionDiv()
      : CInstruction<T>("div")
    {}
 
    CInstructionDiv *factory()
    {
      return new CInstructionDiv;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** register number */
    unsigned m_regidx2;
    /** register number */
    unsigned m_regidx3;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionDiv<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 3)
    throw CInstructionError("Invalid paramater count - must be 3");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx2 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx3 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionDiv<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  super::checkRegister(cpu, m_regidx2);
  super::checkRegister(cpu, m_regidx3);
  cpu->getRegisters()[ m_regidx1 ] = cpu->getRegisters()[ m_regidx2 ]
    / cpu->getRegisters()[ m_regidx3 ];
}
 
/*============================================================================*/
 
/**
 * @class CInstructionLoad
 *
 * Implementation of assembler command "load"
 * Syntax: load R1, R2
 *   (R1 = memory[R2])
 */
template <class T>
class CInstructionLoad
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionLoad()
      : CInstruction<T>("load")
    {}
 
    CInstructionLoad *factory()
    {
      return new CInstructionLoad;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** register number */
    unsigned m_regidx2;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionLoad<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 2)
    throw CInstructionError("Invalid paramater count - must be 2");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx2 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionLoad<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  assert(cpu->getMemory() != NULL);
  super::checkRegister(cpu, m_regidx1);
  super::checkRegister(cpu, m_regidx2);
  T val(cpu->getRegisters()[ m_regidx2 ]);
  cpu->getRegisters()[ m_regidx1 ] = (*cpu->getMemory())[ val ];
}
 
/*============================================================================*/
 
/**
 * @class CInstructionStore
 *
 * Implementation of assembler command "store"
 * Syntax: store R1, R2
 *   (memory[R2] = R1)
 */
template <class T>
class CInstructionStore
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionStore()
      : CInstruction<T>("store")
    {}
 
    CInstructionStore *factory()
    {
      return new CInstructionStore;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** register number */
    unsigned m_regidx2;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionStore<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 2)
    throw CInstructionError("Invalid paramater count - must be 2");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
  m_regidx2 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionStore<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  assert(cpu->getMemory() != NULL);
  super::checkRegister(cpu, m_regidx1);
  super::checkRegister(cpu, m_regidx2);
  T val(cpu->getRegisters()[ m_regidx2 ]);
  (*cpu->getMemory())[ val ] = cpu->getRegisters()[ m_regidx1 ];
}
 
/*============================================================================*/
 
/**
 * @class CInstructionTest
 *
 * Implementation of assembler command "test"
 * Syntax: test R1
 *   (R1 == 0: zeroflag: true, R1 < 0: signflag: true)
 */
template <class T>
class CInstructionTest
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionTest()
      : CInstruction<T>("test")
    {}
 
    CInstructionTest *factory()
    {
      return new CInstructionTest;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionTest<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 1)
    throw CInstructionError("Invalid paramater count - must be 1");
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionTest<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  if (cpu->getRegisters()[ m_regidx1 ] == T(0))
    cpu->setFlagZero(true);
  if (cpu->getRegisters()[ m_regidx1 ] < T(0))
    cpu->setFlagSign(true);
}
 
/*============================================================================*/
 
/**
 * @class CInstructionLabel
 *
 * Implementation of assembler command "label"
 * Syntax: label name:
 */
template <class T>
class CInstructionLabel
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionLabel()
      : CInstruction<T>("label")
    {}
 
    CInstructionLabel *factory()
    {
      return new CInstructionLabel;
    }
 
    void compile(std::list<std::string>& params)
    {}
 
    void execute(CCPU<T> *cpu)
    {}
};
 
/*============================================================================*/
 
/**
 * @class CInstructionJumpA
 *
 * Implementation of assembler command "jumpa"
 * Syntax: jumpa labelname
 *   (jump to labelname)
 */
template <class T>
class CInstructionJumpA
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionJumpA()
      : CInstruction<T>("jumpa"), m_addr("")
    {}
 
    CInstructionJumpA *factory()
    {
      return new CInstructionJumpA;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** labelname */
    std::string m_addr;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionJumpA<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 1)
    throw CInstructionError("Invalid paramater count - must be 1");
  m_addr = params.front();
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionJumpA<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  assert(cpu->getProgram() != NULL);
  if (m_addr.empty())
    throw CInstructionError("Empty address");
  try
  {
    cpu->getRegisters()[ 0 ] = cpu->getProgram()->findLabel(m_addr);
  }
  catch(CProgramError& ex)
  {
    throw CInstructionError(ex.what());
  }
}
 
/*============================================================================*/
 
/**
 * @class CInstructionJumpZ
 *
 * Implementation of assembler command "jumpz"
 * Syntax: jumpz labelname
 *   (jump to labelname if zeroflag)
 */
template <class T>
class CInstructionJumpZ
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionJumpZ()
      : CInstruction<T>("jumpz"), m_addr("")
    {}
 
    CInstructionJumpZ *factory()
    {
      return new CInstructionJumpZ;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** labelname */
    std::string m_addr;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionJumpZ<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 1)
    throw CInstructionError("Invalid paramater count - must be 1");
  m_addr = params.front();
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionJumpZ<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  assert(cpu->getProgram() != NULL);
  if (!cpu->getFlagZero())
    return;
  if (m_addr.empty())
    throw CInstructionError("Empty address");
  try
  {
    cpu->getRegisters()[ 0 ] = cpu->getProgram()->findLabel(m_addr);
  }
  catch(CProgramError& ex)
  {
    throw CInstructionError(ex.what());
  }
}
 
/*============================================================================*/
 
/**
 * @class CInstructionJumpS
 *
 * Implementation of assembler command "jumps"
 * Syntax: jumps labelname
 *   (jump to labelname if signflag)
 */
template <class T>
class CInstructionJumpS
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
 
  public:
    CInstructionJumpS()
      : CInstruction<T>("jumps"), m_addr("")
    {}
 
    CInstructionJumpS *factory()
    {
      return new CInstructionJumpS;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** labelname */
    std::string m_addr;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionJumpS<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 1)
    throw CInstructionError("Invalid paramater count - must be 1");
  m_addr = params.front();
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionJumpS<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  assert(cpu->getProgram() != NULL);
  if (!cpu->getFlagSign())
    return;
  if (m_addr.empty())
    throw CInstructionError("Empty address");
  try
  {
    cpu->getRegisters()[ 0 ] = cpu->getProgram()->findLabel(m_addr);
  }
  catch(CProgramError& ex)
  {
    throw CInstructionError(ex.what());
  }
}
 
/*============================================================================*/
 
/**
 * @class CInstructionWrite
 *
 * Implementation of assembler command "write"
 * Syntax: write DEV, R1
 *   (write R1 to DEV, which is a name of a display)
 */
template <class T>
class CInstructionWrite
 : public CInstruction<T>
{
  typedef CInstruction<T> super;
  typedef typename std::set<CDisplay<T> *>::iterator setiterator;
 
  public:
    CInstructionWrite()
      : CInstruction<T>("write"), m_dev("")
    {}
 
    CInstructionWrite *factory()
    {
      return new CInstructionWrite;
    }
 
    void compile(std::list<std::string>& params);
    void execute(CCPU<T> *cpu);
 
  protected:
    /** register number */
    unsigned m_regidx1;
    /** device name */
    std::string m_dev;
};
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionWrite<T>::compile(std::list<std::string>& params)
{
  if (params.size() != 2)
    throw CInstructionError("Invalid paramater count - must be 2");
  m_dev = params.front();
  params.pop_front();
  m_regidx1 = super::parseRegister(params.front());
  params.pop_front();
}
 
/*----------------------------------------------------------------------------*/
 
template <class T>
void CInstructionWrite<T>::execute(CCPU<T> *cpu)
{
  assert(cpu != NULL);
  super::checkRegister(cpu, m_regidx1);
  if (m_dev.empty())
    throw CInstructionError("Empty device");
 
  CDisplay<T> *display = NULL;
  std::set<CDisplay<T> *> displays = cpu->getDisplays();
  for(setiterator it = displays.begin(); it != displays.end(); ++it)
  {
    if ((*it)->getName() == m_dev)
    {
      display = *it;
      break;
    }
  }
  if (display == NULL)
    throw CInstructionError("Unknown display");
 
  display->display(cpu->getRegisters()[ m_regidx1 ]);
}
 
#endif
 
/* vim: set et sw=2 ts=2: */