/** * @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 #include #include #include #include #include #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 void cpu_run(string& me, po::variables_map& vm, unsigned registers, T& datatype) { CMem memory; /* optionally initialize memory from file */ if (vm.count("memory")) { string memoryfile(vm["memory"].as()); 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 program; string programfile(vm["compile"].as()); 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 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(), "input format") ("compile,c", po::value(), "input programfile") ("memory,m", po::value(), "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 ] -c [-m ]" << endl; cout << desc << endl; return 0; } /* create memory, program and cpu from templates */ try { if (vm.count("format")) { string format(vm["format"].as()); if (format == "s") { CDatSet datatype(0); cpu_run(me, vm, REGISTERS, datatype); } else { unsigned bc; try { bc = boost::lexical_cast(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(me, vm, REGISTERS, datatype); } } else { CDat datatype(0); cpu_run >(me, vm, REGISTERS, datatype); } } catch(runtime_error& ex) { cerr << me << ": " << ex.what() << endl; return 1; } return 0; } /* vim: set et sw=2 ts=2: */