#include #include #include 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 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 class Ram { private: public: vector 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 class Program { private: public: vector 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 inbuf; queue 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 rstor{this}; Mmu> ram{rstor}; Program pstor{this}; Mmu> 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 &); }; }