Download | Plain Text | Line Numbers


/**
 * @module mycpu
 * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348)
 * @brief  mycpu executes a programfile (in simple assembler) by parsing the
 *         programfile first. This creates a vector of instructions, which will
 *         be executed in linear order (except jumps) afterwards. In order to
 *         initialize the memory of the cpu before execution an optional
 *         memoryfile can be passed as commandline option.
 * @date   26.05.2009
 * @par Exercise
 *      4
 */
 
#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <stdlib.h>
#include "cdat.h"
#include "cdatset.h"
#include "cdatn.h"
#include "ccpu.h"
#include "cmem.h"
#include "cprogram.h"
 
#define REGISTERS 256
 
using namespace std;
namespace po = boost::program_options;
 
/**
 * @func   cpu_run
 * @brief  template for executing cpu with different datatype
 * @param  me         string to name of me
 * @param  vm         po::variables_map
 * @param  registers  number of registers
 * @param  datatype   instance of datatype
 * @return -
 * @globalvars none
 * @exception  none
 * @pre  none
 * @post none
 */
template<class T>
void cpu_run(string& me, po::variables_map& vm, unsigned registers, T& datatype)
{
  CMem<T> memory;
  /* optionally initialize memory from file */
  if (vm.count("memory"))
  {
    string memoryfile(vm["memory"].as<string>());
    ifstream file(memoryfile.c_str(), ios::in);
    if (!file.is_open())
      throw runtime_error("Unable to open memoryfile '" + memoryfile + "' for reading.");
 
    try
    {
      memory.initialize(file, datatype);
      file.close();
    }
    catch(CMemError& ex)
    {
      file.close();
      std::stringstream sstr;
      sstr << "Error while reading from memoryfile:" << endl << "  " << ex.what();
      throw runtime_error(sstr.str());
    }
 
#if DEBUG
    memory.dump(cerr);
#endif
  }
 
  /* create program instance */
  CProgram<T> program;
  string programfile(vm["compile"].as<string>());
  ifstream file(programfile.c_str(), ios::in);
  if (!file.is_open())
    throw runtime_error("Unable to open programfile '" + programfile + "' for reading.");
 
  try
  {
    program.compile(file);
    file.close();
  }
  catch(CProgramError& ex)
  {
    file.close();
    std::stringstream sstr;
    sstr << "Error while compiling programfile:" << endl << "  " << ex.what();
    throw runtime_error(sstr.str());
  }
 
#if DEBUG
  program.dump(cerr);
#endif
 
  /* execute the program */
  CCPU<T> cpu(registers, datatype);
  try
  {
    cpu.setMemory(&memory);
    cpu.setProgram(&program);
    cpu.run();
#if DEBUG
    //cpu.dumpRegisters(cerr);
#endif
  }
  catch(CCPUError& ex)
  {
    std::stringstream sstr;
    sstr << "Error while executing program:" << endl << "  " << ex.what();
#if DEBUG
    memory.dump(cerr);
#endif
    throw runtime_error(sstr.str());
  }
}
 
/**
 * @func   main
 * @brief  program entry point
 * @param  argc  standard parameter of main
 * @param  argv  standard parameter of main
 * @return 0 on success, not 0 otherwise
 * @globalvars none
 * @exception  none
 * @pre  none
 * @post terminate with 0 if success else 1. 
 *
 * parse commandline options, create and initialize memory,
 * create cprogram instance, which parses the programfile and
 * execute CCPU::run()
 * On error print error message to stderr.
 * Unknown commandline options will print a usage message.
 */
int main(int argc, char* argv[])
{
  string me(argv[0]);
 
  /* define commandline options */
  po::options_description desc("Allowed options");
  desc.add_options()
    ("help,h",    "this help message")
    ("format,f",  po::value<string>(), "input format")
    ("compile,c", po::value<string>(), "input programfile")
    ("memory,m",  po::value<string>(), "input memoryfile");
 
  /* parse commandline options */
  po::variables_map vm;
  try
  {
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);
  }
  catch(po::error& ex)
  {
    cerr << me << ": Error: " << ex.what() << endl;
    return 1;
  }
 
  /* print usage upon request or missing params */
  if (vm.count("help") || !vm.count("compile"))
  {
    cout << "Usage: " << me << " [-f <format>] -c <programfile> [-m <memoryfile>]" << endl;
    cout << desc << endl;
    return 0;
  }
 
  /* create memory, program and cpu from templates */
  try
  {
    if (vm.count("format"))
    {
      string format(vm["format"].as<string>());
      if (format == "s")
      {
        CDatSet datatype(0);
        cpu_run<CDatSet>(me, vm, REGISTERS, datatype);
      }
      else
      {
        unsigned bc;
        try
        {
          bc = boost::lexical_cast<unsigned>(format);
        }
        catch(boost::bad_lexical_cast& ex)
        {
          cerr << me << ": Paramater 'format' has invalid or unknown format." << endl;
          return 1;
        }
 
        if (bc < 2 || bc > 32)
        {
          cerr << me << ": Paramater 'format' must be inbetween 2 and 32." << endl;
          return 1;
        }
 
        CDatN datatype(0, bc);
        cpu_run<CDatN>(me, vm, REGISTERS, datatype);
      }
    }
    else
    {
      CDat<int> datatype(0);
      cpu_run<CDat<int> >(me, vm, REGISTERS, datatype);
    }
  }
  catch(runtime_error& ex)
  {
    cerr << me << ": " << ex.what() << endl;
    return 1;
  }
 
  return 0;
}
 
/* vim: set et sw=2 ts=2: */