diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | main.cpp | 74 | ||||
-rw-r--r-- | main.hpp | 23 |
3 files changed, 75 insertions, 24 deletions
@@ -1,2 +1,4 @@ .gdb_history ov +a.out +core @@ -1,4 +1,4 @@ -#include <iostream> /* src, dest, instr, padding */ +#include <iostream> #include "main.hpp" using namespace std; using namespace ov; @@ -20,8 +20,15 @@ namespace ov { if (val) ov->pc |= 1 << addr; } /* we fall through */ - if (addr >= (unsigned int) 1 << ov->ras) + 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 */ @@ -38,19 +45,17 @@ namespace ov { } ov->io[addr-ov->pas] = val; } /* we fall through, but only if !BUF__ */ - storage[addr] = val; + storage.at(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); + storage.resize(ov->rs+ov->pas, 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 + storage.resize(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 () { @@ -76,8 +81,12 @@ namespace ov { 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]; + /* if (pm(pc++).p) // reading from progmem + for (int i = 0; i < pas; i++) + b[i] = [pm[pc].serialized]; + else */ + 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; @@ -132,11 +141,10 @@ namespace ov { throw BufferingRequired; if (inbuf.size() < 8) throw NotAvailable; - for (int x = 7; x >= 0; x--) { + 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 Ov::deserialize (const char * c) { // treats c as array of is size struct instr r; for (int i = 0; i < ras; i++) if (c[i/8] & 1 << (i%8-8)) @@ -150,14 +158,48 @@ namespace ov { 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 (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 (int j = 0; j < ras; j++) { + 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 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) + if ((o+s) % is) throw NotAligned; - for (unsigned int i = 0; i < s; i += is) { + for (unsigned int i = 0; i < s; i += is) pm[o+i/s] = deserialize(c.c_str()+i); + } + void Ov::pd (ostream & o) { + o << "pc: " << pc << "\t" << "opts:" << (opts[BUFOUT] ? " BUFOUT" : "") + << (opts[BUFIN] ? " BUFIN" : "") << endl; + o << "ram:"; + for (unsigned int i = 0; i < rs; i++) { + if (i % 8 == 0) + o << " "; + o << "" << ram[i]; +#pragma message typeof(ram[i]) } + o << endl; } } int main (void /* int argc, char ** argv */) { @@ -165,5 +207,9 @@ int main (void /* int argc, char ** argv */) { << "Stanard input is ready to accept a binary." << endl; Ov ov; ov.deserialize(); + while (1) { + ov.pd(cout); + ov.step(); + } return 0; } @@ -1,12 +1,14 @@ #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 - BUFCLR, // clears whatever is in the buffer + 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 { @@ -24,7 +26,7 @@ namespace ov { unsigned int s = 0; // source unsigned int d = 0; // destination bool i = 0; // instruction - bool p = 0; // enobitni padding, lahko za metainštrukcije + 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: @@ -57,8 +59,8 @@ namespace ov { class Ov; template<typename value_type, typename index_type> class Ram { private: - vector<value_type> storage; public: + vector<value_type> storage; Ov * ov; value_type peek (index_type); void poke(index_type, value_type); @@ -67,7 +69,7 @@ namespace 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 vektor in posledično binarno datoteko. + * 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 @@ -76,8 +78,8 @@ namespace ov { * */ template<typename value_type, typename index_type> class Program { private: - vector<value_type> storage; public: + vector<value_type> storage; Ov * ov; value_type & peek (index_type addr) { return storage[addr]; @@ -133,7 +135,7 @@ namespace ov { 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) { + : is(is), pas(pas) { // add bound checks for (int i = 0; i < OPTSLEN; i++) opts[i] = 0; for (int i = 0; i < IOLEN; i++) @@ -144,8 +146,9 @@ namespace ov { char outc (void); void in (bool); void inc (char); - struct instr deserialize (const char *); + struct instr deserialize (const char [sizeof(struct instr)]); void deserialize (istream &, unsigned int); - void pd (ostream); // print debug + string serialize (struct instr * i, unsigned int); + void pd (ostream &); }; } |