summaryrefslogtreecommitdiffstats
path: root/main.hpp
blob: 58a73376500e95c8414778ba0615eb633400274b (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
#include <vector>
#include <queue>
#include <string>
namespace ov {
	using namespace std;
	enum opts { // opts are pas-1 bits aftr last ram ptr (2**ras)-1 and can be w/r from prg
		DEFAULT,
		BUFOUT,		// output from program in VM is always possible and no blocks
		BUFIN,		// input to program in VM is always possible and no blocks
		BUFINCLR,	// clears whatever is in the input buffer
		BUFOUTCLR,	// clears whatever is in the output buffer
		OPTSLEN
	}; // read those last bits with the COPY instruction with source/dest on last pointer
	enum iobits {
		INA,	// input available, clear when read
		IN,	// input bit
		OUTA,	// output available, set when have output, cleared by VM when wrote
		OUT,	// output bit
		IOLEN
	};
	enum instrs {
		COPY,
		NAND
	};
	struct instr {			// deserializirana inštrukcija
		unsigned int s = 0;	// source
		unsigned int d = 0;	// destination
		bool i = 0;		// instruction
		bool p = 0;		// enobitni padding, lahko za metainštrukcije, pri COPY je že
	};	// privzeto inicializiran na NOOP inštrukcijo
	template<typename value_type, typename index_type, class Memory> class Mmu {
		private:
			class Cell {
				private:
					friend class Mmu;
					Mmu & mmu;
					index_type index;
					Cell (Mmu & mmu, index_type index)
						: mmu(mmu), index(index) {}
				public:
					operator value_type (void) {
						return mmu.memory.peek(index);
					}
					value_type operator= (value_type value) {
						mmu.memory.poke(index, value);
						return value;
					}
			};
		public:
			Memory & memory;
			Mmu (Memory & memory) : memory(memory) {}
			Cell operator[] (index_type index) {
				return Cell(*this, index);
			}
			value_type & operator() (index_type index) {
				return memory.peek(index);
			}
	};
	class Ov;									
	template<typename value_type, typename index_type> class Ram {
		private:
		public:
			vector<value_type> storage;
			Ov * ov;
			value_type peek (index_type);
			void poke(index_type, value_type);
			Ram (Ov *);
	};
	/* v Program (memory) bi lahko uporabili metainštrukcije (tisti padding bit) v
	 * vsaki inštrukciji in v metainštrukcijah reprezentirali assembly org (lokacijo).
	 * s tem bi lahko imeli npr. 128 biten program counter in s tem zelo preproste jumpe,
	 * ne bi pa bilo treba narediti 2^128 vektorja in posledično binarne datoteke.
	 * Tak način bi bilo verjetno težko implementirati na dejanski strojni opremi,
	 * tukaj pa bi v enem passu čez cel deserializan program memory zaznali te org
	 * metainštrukcije in naredili neko tabelo oziroma prevajalnik program counterja
	 * v lokacijo v vektorju. problem je, da bi se morala prevajalska tabela vsakič znova
	 * regenerirati, ko spreminjamo program memory.
	 * */
	template<typename value_type, typename index_type> class Program {
		private:
		public:
			vector<value_type> storage;
			Ov * ov;
			value_type & peek (index_type addr) {
				return storage[addr];
			}
			void poke (index_type addr, value_type val) {
				storage[addr] = val;
			}
			Program (Ov *);
	};
	class Ov {
		private:
		public:
			queue<bool> inbuf;
			queue<bool> outbuf;
#define IS2RAS(is) ((is*8-2)/2)
			class ras {						// IS		
				private:					// IT		
				public:						// REALLY	
					unsigned short int & is;		// THIS		
					operator unsigned short int (void) {	// HARD		
						return IS2RAS(is);		// TO		
					}					// DEFINE	
					ras (class Ov * ov) : is(ov->is) {}	// A		
			};							// GETTER	
			ras ras{this};						// FUNCTION	
			class rs {
				private:
				public:
					unsigned short int & is;
					operator unsigned int (void) {
						return 1 << IS2RAS(is);
					}
					rs (class Ov * ov) : is(ov->is) {}
			};
			rs rs{this};
			class ps {
				private:
				public:
					unsigned short int & pas;
					operator unsigned int (void) {
						return 1 << pas;
					}
					ps (class Ov * ov) : pas(ov->pas) {}
			};
			ps ps{this};
			unsigned short int is;
			unsigned short int pas;
			bool io[IOLEN];
			bool opts[OPTSLEN];
			unsigned int pc = 0; /* where the program starts --- at zero or where? */
			Ram<bool, unsigned int> rstor{this};
			Mmu<bool, unsigned int, class Ram<bool, unsigned int>> ram{rstor};
			Program<struct instr, unsigned int> pstor{this};
			Mmu<struct instr, unsigned, class Program<struct instr, unsigned>> pm{pstor};
			Ov (unsigned short int is = 2, unsigned short int pas = 16)
				: is(is), pas(pas) { // add bound checks
				for (int i = 0; i < OPTSLEN; i++)
					opts[i] = 0;
				for (int i = 0; i < IOLEN; i++)
					io[i] = 0;
			}
			void step (void);
			bool out (void);
			char outc (void);
			void in (bool);
			void inc (char);
			struct instr deserialize (const char [sizeof(struct instr)]);
			void deserialize (istream &, unsigned int);
			string serialize (struct instr * i, unsigned int);
			void pd (ostream &);
	};
}