summaryrefslogblamecommitdiffstats
path: root/main.cpp
blob: 74b9fad53b609d8c704ffb145940055ccc0d596d (plain) (tree)
1
2
3
4
5
6
7






                                                                        





                                                               




                                                                                  
                                                           
                                
                                                                
                                       


                                                             

                                                          
                                                              


                                                           















                                                                                                     
                                       



                                                          


                                                                     
                 
         

                                                                                                  



                                               
                                  
                                                                 
                                                                     


                                                                                                      
                                                                     
                                                                      
                                                             
                                                             

                                      
                                                                             




















                                                                                                    
                              

                                                                          























                                                                                                    
                                            
                                       
                                                        
                                                                                       
                               

                                                          
                                              



                                                          





                                              


                                                                  



                                                                          
                         




                                                                          
                         
                                                              
                                    

                                                                      
                                    
                                                                      


                                                                                                     


                                                

                                                                                             


                                                             
                                          
                               
                                         
                                                        
                                                                
         




                                                                                               
                            
                                                         

                                         
                                                     
                 
                          
         























































                                                                                           
 

                                                                           
              









                                                                                         
                   
                        

                          

                 
#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 << (ov->pas-1-addr);
		if (addr-ov->pas < IOLEN) {
			return ov->io[addr-ov->pas];
		}
		if (addr >= (unsigned int) 1 << ov->ras())
			return ov->opts[addr-(1 << ov->ras())];
		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 << (ov->pas-1-addr));
			if (val)
				ov->pc |= 1 << (ov->pas-1-addr);
		} /* we fall through */
		if (addr >= ov->rs()) {
			ov->opts[addr-ov->rs()] = val;
			if (val && addr-ov->rs() == BUFINCLR)
				while (!ov->inbuf.empty())
					ov->inbuf.pop();
			if (val && addr-ov->rs() == BUFOUTCLR)
				while (!ov->outbuf.empty())
					ov->outbuf.pop();
		}
		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.at(addr) = val;
	}
	template<typename value_type, typename index_type>
	Ram<value_type, index_type>::Ram (Ov * ov) {
		this->ov = ov;
		storage.resize(ov->rs()+ov->pas, false);
		for (unsigned int i = 0; i > ov->rs()+ov->pas; i++) {
			storage[i] = false;
		}
	}
	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
		struct instr š = p.peek(pc++);
		if (pc >= ps())
			pc = 0;
		switch (š.i) {
			case COPY:
				if (š.p) // reading from progmem
					for (int i = 0; i < pas; i++)
						b[i] = 1 << (7-š.s%pas%8)&serialize(p.peek(š.s/pas))
							.c_str()[š.s%pas/8];
				else
					for (int i = 0; i < pas; i++)
						b[i] = r.peek(š.s+i);
				for (int i = 0; i < pas; i++)
					r.poke(š.d+i, b[i]);
				break;
			case NAND:
				r.poke(š.d, !(r.peek(š.s) & r.peek(š.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 = '\0';
		for (int i = 0; i < 8; i++) { // bitwise endianness is big
			bool b = outbuf.front();
			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 c as array of is size
		struct instr r;
		for (unsigned int i = 0; i < ras(); i++) {
			if (c[i/8] & 1 << (7-i%8))
				r.s |= 1 << i;
		}
		for (unsigned int i = 0; i < ras(); i++) {
			unsigned int j = i+ras();
			if (c[j/8] & 1 << (7-j%8))
				r.d |= 1 << i;
		}
		r.i = c[is-1] & 1 << 6;
		r.p = c[is-1] & 1 << 7;
		return r;
	}
	string Ov::serialize (struct instr * š, unsigned int n) {
		char r[sizeof(š)*n];
		for (unsigned int i = 0; i < n; i++) {
			for (unsigned int j = 0; j < ras(); j++) {
				r[i*is+j/8] &= ~(1 << ((ras()-1)-j));
				if (š[i].s & 1 << ((ras()-1)-j))
					r[i*is+j/8] |= 1 << ((ras()-1)-j);
			}
			for (unsigned int j = 0; j < ras(); j++) {
				unsigned int k = j+ras();
				r[i*is+k/8] &= ~(1 << ((ras()-1)-j));
				if (š[i].d & 1 << ((ras()-1)-j))
					r[i*is+k/8] |= 1 << ((ras()-1)-j);
			}
			r[i*is+(2*ras())/8] &= 1 << (ras()-2);
			if (š[i].i)
				r[i*is+(2*ras())/8] |= 1 << (ras()-2);
			r[i*is+(2*ras())/8] &= 1 << (ras()-1);
			if (š[i].p)
				r[i*is+(2*ras())/8] |= 1 << (ras()-1);
		}
		return string(r); // ugly hack, C/C++ in 2022 still can't return arrays from function
	} // serialize(&pstor.storage[0], pstor.storage.size) is valid, because pm has no special MMU
	string Ov::serialize (struct instr š) {
		return serialize(&š, 1);
	}
	void Ov::deserialize (istream & v = cin, unsigned int o = 0) {
		string c((istreambuf_iterator<char>(v)), istreambuf_iterator<char>()); // eof
		deserialize(c, o);
	}
	void Ov::deserialize (string c, unsigned int o = 0) {
		unsigned int s = c.size();
		if ((o+s) % is)
			throw NotAligned;
		for (unsigned int i = 0; i < s; i += is)
			p.poke(o+i/s, deserialize(c.c_str()+i));
	}
	void Ov::pd (ostream & o = clog) {
		o << "pc: " << pc << "\topts:" << (opts[BUFOUT] ? " BUFOUT" : "")
			<< (opts[BUFIN] ? " BUFIN" : "") << "\tinstruction: " <<
			(p.peek(pc).i == COPY ? "COPY from " : "NAND from ") << p.peek(pc).s <<
			"\tto " << p.peek(pc).d << "\twith meta bit " << p.peek(pc).p << endl;
		o << "ram:";
		for (unsigned int i = 0; i < rs(); i++) {
			if (i % 8 == 0)
				o << " ";
			o << (r.peek(i) ? "1" : "0");
		}
		o << endl;
	}
	vector<struct instr> assembler (string v) {
		map<string, struct def> defs;
		vector<struct instr>;
		int hiaddr = 0;
		int i = 0;
		while (i < v.length) {
			if (i && v[i-1] == '\n' && !v.find("%define ", i)) {
				i += strlen("%define ");
				int ž = s.find('(', i);
				string dn("");
				if (ž == string::npos) {
					if ((ž = s.find(' ', i)) == string::npos)
						if ((ž = s.find('\n', i)) == string::npos)
							throw EndlessArgument;
					dn = s.substr(i, ž);
				} else {
					dn = s.substr(i, s.find('(', ž));
					int k = s.find(')', ž);
					if (k == string::npos)
						throw EndlessArgument;
					string args = s.substr(ž+1, k);
					while ((k = s.find(',', ž)) != string::npos) {
						defs[dn].args.push_back(s.substr(ž, k));
						ž = k+1;
					}
					i = s.find(')', ž);
					defs[dn].args.push_back(s.substr(ž, i));
				}
				i++;
				while (s[s.find('\n', i)-1] == '\\') {
					defs[dn].body.append(s.substr(i, s.find('\n', i)));
					i = s.find('\n', i)+1;
				}
				defs[dn].body.append(s.substr(i, s.find('\n', i)));
				i = s.find('\n', i)+1;
			}
			if (i && v[i-1] == '\n' && !v.find("%macro ", i)) {
				i += strlen("%macro ");
				if ((ž = s.find(' ', i)) == string::npos)
					throw EndlessArgument;
				string dn = s.substr(i, ž++);
				n = atoi(s.substring(++i));
				for (int j = 0; j < n; j++)
					defs[dn].args.push_back("%" << n+1);
				if ((i = s.find('\n', i)) == string::npos)
					throw EndlessBlock;
				i++;
				while (s.find("%endmacro", i)) {
					n = s.find('\n', i)+1;
					if (n == str::npos)
						throw EndmacroMissing;
					defs[dn].body.append(s.substr(i, n));
				}
			}
		}
	}
}
int main (int argc, char ** argv) {
	clog << "OV stands for OB (One Bit) VM (Virtual Machine)." << endl;
	Ov ov;
	ov.pd();
	if (argc < 2 || !argv[1]) {
		clog << "Stanard input is ready to accept a binary." << endl
			<< "You can also specify the binary filename in argv[1]" << endl;
		ov.deserialize();
	} else { 
		ifstream exe = ifstream(argv[1]);
		ov.pd();
		ov.deserialize(exe);
	}
	while (1) {
		ov.pd();
		ov.step();
	}
	return 0;
}