#include #include #include #include #include #include #include namespace ov { using namespace std; struct NotImplemented : public exception { 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; struct AssemblerFatal : public exception { const char * what () const throw () { return "Fatal error in assembler."; } } AssemblerFatal; struct SyntaxError : AssemblerFatal { const char * what () const throw () { return "Fatal syntax error in assembler."; } } SyntaxError; struct EndlessArgument : public SyntaxError { const char * what () const throw () { return "Some builtin preprocessor command does not have enough arguments."; } } EndlessArgument; struct EndlessBlock : public SyntaxError { const char * what () const throw () { return "Some builtin preprocessor block %* is not terminated with %end*."; } } EndlessBlock; 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 struct def { vector args; string body; }; 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: index_type hiaddr; vector storage; const struct instr empty; Ov * ov; value_type & peek (index_type addr) { if (addr > hiaddr) { hiaddr = addr; storage.resize(hiaddr+1, empty); } return storage[addr]; } void poke (index_type addr, value_type val) { if (addr > hiaddr) { hiaddr = addr; storage.resize(hiaddr+1, empty /* avoid leaking memory */); } storage[addr] = val; } index_type length () { return hiaddr+1; } Program (Ov * ov) : ov(ov) { hiaddr = 0; storage.push_back(empty); // we don't want to leak memory contents } }; class Ov { private: public: queue inbuf; queue outbuf; unsigned int ras (void) { return (is*8-2)/2; } unsigned int rs (void) { return 1 << ras(); } unsigned int ps (void) { return 1 << pas; } 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 r{this}; Program p{this}; Ov (unsigned short int is = 2, unsigned short int pas = 16) : is(is), pas(pas) { // TODO: check 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); void deserialize (string, unsigned int); string serialize (struct instr *, unsigned int); string serialize (struct instr); void pd (ostream &); }; vector assembler (string); }