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: */