summaryrefslogblamecommitdiffstats
path: root/main.cpp
blob: 7254b1e280bb2569cf8a9156cd1c82ed14104230 (plain) (tree)








































































































































































                                                                                                     
#include <iostream>	/* src, dest, instr, padding */
#include "main.hpp"
using namespace std;
using namespace ov;
namespace ov {
	template<typename value_type, typename index_type>
	value_type Ram<value_type, index_type>::peek (index_type addr) {
		if (addr < ov->pas)
			return ov->pc & 1 << addr;
		if (addr >= (unsigned int) 1 << ov->ras)
			return ov->opts[addr-(1 << ov->ras)];
		if (addr-ov->pas < IOLEN)
			return ov->io[addr-ov->rs];
		return storage[addr];
	}
	template<typename value_type, typename index_type>
	void Ram<value_type, index_type>::poke (index_type addr, value_type val) {
		if (addr < ov->pas) {
			ov->pc &= ~(1 << addr);
			if (val)
				ov->pc |= 1 << addr;
		} /* we fall through */
		if (addr >= (unsigned int) 1 << ov->ras)
			ov->opts[addr-ov->rs] = val;
		if (addr >= ov->pas && addr-ov->pas < IOLEN) {
			if (ov->opts[BUFIN] && addr-ov->pas == INA && val == 0) { /* machine read */
				if (!ov->inbuf.empty()) { /* and wants more. oh, it looks like we */
					ov->io[IN] = ov->inbuf.front(); /* have more. we pop the */
					ov->inbuf.pop(); /* queue, set the input available bit and */
					ov->io[INA] = 1; /* return, so actual set will not be */
					return; /* applied, because input is ready. */
				} /* if we have no input, we just store the zero */
			} /* we do similar things for output. whenever the machine is ready to */
			if (ov->opts[BUFOUT] && addr-ov->pas == OUTA && val == 1) { /* output, it */
				ov->outbuf.push(ov->io[OUT]); /* sets OUTA bit. we push the OUT */
				ov->io[OUT] = 0; /* value into the output queue and clear OUTA bit */
				return; /* and therefore indicating the host has read the output. */
			}
			ov->io[addr-ov->pas] = val;
		} /* we fall through, but only if !BUF__ */
		storage[addr] = val;
	}
	template<typename value_type, typename index_type>
	Ram<value_type, index_type>::Ram (Ov * ov) {
		this->ov = ov;
		storage.reserve(ov->rs+ov->pas);
		for (unsigned int i = 0; i <= ov->rs+ov->pas; i++)
			poke(i, 0);
	}
	template<typename value_type, typename index_type>	// inventor did not say about
	Program<value_type, index_type>::Program (Ov * ov) {	// initializing program memory, so I
		this->ov = ov;					// do not do that. but by "spec", ram
		storage.reserve(ov->ps);			// is set to zero and code starts at
	}							// pc == 0, unless of course set with
	struct NotImplemented : public exception {		// Ov::pc.
		const char * what () const throw () {
			return "Not implemented.";
		}
	} NotImplemented;
	struct NotAvailable : public exception {
		const char * what () const throw () {
			return "I/O is currently not available. You can try again.";
		}
	} NotAvailable;
	struct BufferingRequired : public exception {
		const char * what () const throw () {
			return "I/O buffering must be enabled for this function, but it's not.";
		}
	} BufferingRequired;
	struct NotAligned : public exception {
		const char * what () const throw () {
			return "Byte count can't be deserialized without remainder.";
		}
	} NotAligned;
	void Ov::step () {	// ko se izvaja inštrukcija, kaže števec programa na naslednjo.
		bool b[pas]; 	// buffer. you have to first read all and then write for COPY
		switch (pm(pc++).i) { // predstavljaj si, da so oklepaji okoli pc++ oglati (;
			case COPY:
				for (int i = 0; i < pas; i++)
					b[i] = ram[pm(pc).s+i];
				for (int i = 0; i < pas; i++)
					ram[pm(pc).d+i] = b[i];
				break;
			case NAND:
				ram[pm(pc).d] = !(ram[pm(pc).s] & ram[pm(pc).d]);
				break;
		}
	}
	bool Ov::out () { /* output from machine. throw NotAvailable when there's nothing */
		if (opts[BUFOUT]) {
			if (outbuf.empty())
				throw NotAvailable;
			bool o = outbuf.front();
			outbuf.pop(); /* unconveniently, pop returns nothing */
			return o;
		}
		if (!(io[OUTA]))
			throw NotAvailable;
		io[OUTA] = 0;
		return io[OUT];
	} /* if BUFOUT is set in opts, this is read from the buffer instead */
	char Ov::outc () { /* output a byte from machine or throw NotAvailable if not enough bits */
		if (!opts[BUFOUT])
			throw BufferingRequired;
		if (outbuf.size() < 8)
			throw NotAvailable;
		char r;
		for (int i = 0; i < 8; i++) { // bitwise endianness is big
			bool b = outbuf.front();
			r &= ~(1 << (8-i));
			if (b)
				r |= 1 << (8-i);
			outbuf.pop();
		}
		return r;
	} /* buffering must be enabled for this to work. */
	void Ov::in (bool i) { /* input to machine. thrw NotAvailable when program hasn't read */
		if (opts[BUFOUT]) { /* for BUFOUT input we ONLY insert into the queue if machine */
			if (io[INA]) /* "EWOULDBLOCK", in case it can read we put directly to io. */
				inbuf.push(i);
			io[IN] = i;
			io[INA] = 1;
			return;
		}
		if (io[INA]) /* bit is set, so program in VM must first clear the bit. */
			throw NotAvailable;
		io[IN] = i;
		io[INA] = 1;
	} /* if BUFIN is set in opts, this is put to the buffer instead */
	void Ov::inc (char i) { // input a byte to the machine
		if (!opts[BUFIN])
			throw BufferingRequired;
		if (inbuf.size() < 8)
			throw NotAvailable;
		for (int x = 7; x >= 0; x--) {
			in(i & 1 << x);
		}
	} // buffering must be enabled for this to work.
	struct instr Ov::deserialize (const char * c) { // treats i as array of is size
		struct instr r;
		for (int i = 0; i < ras; i++)
			if (c[i/8] & 1 << (i%8-8))
				r.s |= 1 << i;
		for (int i = 0; i < ras; i++) {
			int j = i+ras;
			if (c[j/8] & 1 << (j%8-8))
				r.d |= 1 << i;
		}
		r.i = c[is-1] & 1 << 6;
		r.p = c[is-1] & 1 << 7;
		return r;
	}
	void Ov::deserialize (istream & v = cin, unsigned int o = 0) {
		string c((istreambuf_iterator<char>(v)), istreambuf_iterator<char>()); // eof
		unsigned int s = c.size();
		if (s % 2)
			throw NotAligned;
		for (unsigned int i = 0; i < s; i += is) {
			pm[o+i/s] = deserialize(c.c_str()+i);
		}
	}
}
int main (void /* int argc, char ** argv */) {
	clog << "OV stands for OB (One Bit) VM (Virtual Machine)." << endl
		<< "Stanard input is ready to accept a binary." << endl;
	Ov ov;
	ov.deserialize();
	return 0;
}