#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include "Assembler.h"
#include "VirtualMachine.h"
#include "OS.h"
using namespace std;
OS::OS() {
//Assembler as;
//VirtualMachine vm;
string line;
fstream assembly, objectCode;
fstream in, out, stack;
int base=0, limit = 0;
system("ls *.s > progs");
fstream program;
program.open("progs", ios::in);
if (!program.is_open()) {
cout << "Couldn't open progs" << endl;
exit(1);
}
getline(program, line);
while (!program.eof()) {
objectCode.close();
in.close();
out.close();
stack.close();
limit = 0;
string assemblyFile = line;
int pos = assemblyFile.find(".");
if (pos > assemblyFile.length() || assemblyFile.substr(pos) != ".s") {
cout << "No .s suffix.\n";
exit(2);
}
string name = assemblyFile.substr(0, pos);
string objectFile = name + ".o";
assembly.open(assemblyFile.c_str(), ios::in);
objectCode.open(objectFile.c_str(), ios::out);
if (!assembly.is_open() or !objectCode.is_open()) {
cout << "Couldn't open " << assemblyFile << " and/or " << objectFile << endl;
exit(3);
}
PCB * p = new PCB(name, base, limit);
if (as.assemble(assembly, objectCode)) {
cout << "Assembler Error\n";
assembly.close();
objectCode.close();
exit(4);
}
assembly.close();
objectCode.close();
objectCode.open(objectFile.c_str(), ios::in);
if (!objectCode.is_open()) {
cout << "Couldn't open " << objectFile << endl;
exit(5);
}
string inFile = name + ".in";
string outFile = name + ".out";
string stFile = name + ".st";
system(string("touch " + stFile).c_str());
p->in.open(inFile.c_str(), ios::in);
p->out.open(outFile.c_str(), ios::out);
p->stack.open(stFile.c_str(), ios::in | ios::out);
if (!p->in.is_open() or !p->out.is_open()) {
cout << "Couldn't open " << inFile << " and/or " << outFile << endl;
exit(6);
}
for (p->limit; objectCode >> vm.mem[p->limit + p->base]; p->limit++);
base += p->limit + 1;
jobs.push_back(p);
getline(program, line);
}
list<PCB *>::iterator it = jobs.begin();
while (it != jobs.end()) {
readyQ.push(*it);
it++;
}
}
OS::~OS() {
cout << "Clock = " << sys_time << endl;
PCB *temp;
while(!jobs.empty()) {
temp = jobs.front();
delete temp;
jobs.pop_front();
}
delete running;
}
void OS::run()
{
while (true) {
if(readyQ.empty() && waitQ.empty()) break;
contextSwitch();
if(running) {
loadState();
vm.run(running->in, running->out, TIME_SLICE);
saveState();
}
}
} // run
void OS::loadState() {
vm.pc = running->pc;
for (int i = 0; i < 4; i++)
vm.r[i] = running->r[i];
vm.ir = running->ir;
vm.sr = running->sr;
vm.base = running->base;
vm.limit = running->limit;
vm.sp = running->sp;
running->stack.seekg(0, ios::beg);
for (int i = vm.sp; i < vm.msize and not running->stack.fail(); i++)
running->stack >> vm.mem[i];
}
void OS::saveState() {
running->pc = vm.pc;
for (int i = 0; i < 4; i++)
running->r[i] = vm.r[i];
running->ir = vm.ir;
running->sr = vm.sr;
running->base = vm.base;
running->limit = vm.limit;
running->sp = vm.sp;
running->stack.seekp(0, ios::beg);
for (int i = vm.sp; i < vm.msize; i++)
running->stack << vm.mem[i] << endl;
}
void OS::contextSwitch() {
if(running) {
sys_time += vm.get_clock();
running->cpu_time += vm.get_clock();
}
while(true) {
if(!waitQ.empty()) {
if(waitQ.front()->io_completion <= sys_time) {
readyQ.push(waitQ.front());
waitQ.pop();
}
}
break;
}
int VMReturnStatus = (vm.sr&0xe0)>>5;
if (VMReturnStatus == 0) {
readyQ.push(running);
}
if (VMReturnStatus == 1) {
}
if (VMReturnStatus == 2) {
}
if (VMReturnStatus == 3) {
}
if (VMReturnStatus == 4) {
}
if (VMReturnStatus == 5) {
}
if (VMReturnStatus == 6) {
running->io_completion = running->cpu_time + 27;
waitQ.push(running);
}
if (VMReturnStatus == 7) {
running->io_completion = running->cpu_time + 27;
waitQ.push(running);
}
running = NULL;
vm.sr = 0;
if (!readyQ.empty()) {
running = readyQ.front();
readyQ.pop();
}
sys_time += 5; // time for context switch
}