summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--main.cpp74
-rw-r--r--main.hpp23
3 files changed, 75 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index b379de5..fa90046 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
.gdb_history
ov
+a.out
+core
diff --git a/main.cpp b/main.cpp
index 7254b1e..b0c805f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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;
}
diff --git a/main.hpp b/main.hpp
index f587fab..58a7337 100644
--- a/main.hpp
+++ b/main.hpp
@@ -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 &);
};
}