summaryrefslogtreecommitdiffstats
path: root/main.cpp
blob: 7254b1e280bb2569cf8a9156cd1c82ed14104230 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#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;
}