#ifndef _ASMVM_H_INCLUDED_ #define _ASMVM_H_INCLUDED_ #include #include #include #include #include #include #include // #include namespace wg_asm { using i64 = std::uint64_t; using s64 = std::int64_t; using i32 = std::uint32_t; using s32 = std::int32_t; using f64 = double; using str = std::array; template using is_valid_word = std::conjunction< std::bool_constant, std::is_trivially_copyable >; template inline constexpr bool is_valid_word_v = is_valid_word::value; template , std::is_trivially_copyable , std::is_trivially_copyable >>> T word_cast(F v) { T ret{}; std::memcpy(&ret, &v, sizeof(T)); return ret; } static_assert(is_valid_word_v, ""); static_assert(is_valid_word_v, ""); static_assert(is_valid_word_v, ""); static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, "little-endian host required"); struct pointer { //pointer can only be constructed explicitly constexpr explicit pointer(i32 _p, i32 _l = 1) : p(_p), l(_l) {} constexpr explicit pointer(i64 w) : p(static_cast(w)) , l(static_cast(w>>32)) {} constexpr operator i64() const {return (i64(l)<<32|p);} i32 p; i32 l; }; class alignas(8) word { public: constexpr word(i64 v = 0) : val(v) {} constexpr word(s64 v) : val(static_cast(v)) {} //word from pointer, length constexpr word(i32 p, i32 l) : val(i64(l)<<32|p) {} //pointer->word implicit constexpr word(pointer p) : val(p) {} constexpr word(f64 v) : val(word_cast(v)) {} constexpr word(const str& v) : val(word_cast(v)) {} constexpr word& operator=(const word& o) = default; constexpr operator i64() const {return val;} constexpr operator f64() const {return word_cast(val);} constexpr operator str() const {return word_cast(val);} private: i64 val; }; struct instruction { unsigned long long opcode : 16, cond: 1, indirect2: 1, addr2: 6, immediate1: 20, immediate2: 20; constexpr instruction() : opcode(0) , cond(0) , indirect2(0) , addr2(0) , immediate1(0) , immediate2(0) {} constexpr instruction(i64 s) : opcode(s&65535) , cond((s>>16)&1u) , indirect2((s>>17)&1u) , addr2((s>>18)&63u) , immediate1((s>>24)&0x0FFFFFu) , immediate2((s>>44)&0x0FFFFFu) {} constexpr instruction(str s) : opcode(static_cast(s[1])<<8 | s[0]) , cond(s[2]&1), indirect2((s[2]>>1)&1) , addr2((s[2]>>2)&63) , immediate1(static_cast(s[5]&15)<<16 | static_cast(s[4])<<8 | s[3]) , immediate2(s[7]<<12 | s[6]<<4 | (s[5]>>4)) {} constexpr bool operator==(const instruction& other) const { return (opcode == other.opcode) && (cond == other.cond) && (indirect2 == other.indirect2) && (addr2 == other.addr2) && (immediate1 == other.immediate1) && (immediate2 == other.immediate2) ;//*/ // return std::memcmp(this, &other, sizeof(instruction)) == 0; } constexpr bool operator!=(const instruction& other) const {return !(*this == other);} }; constexpr bool _can_use_instruction_struct_helper() { if constexpr (is_valid_word_v) { // auto test = std::bit_cast(str{1,0,0,0,0,0,0,0}); // return test.immediate2 == 1; return true; } else return false; } constexpr bool can_use_instruction_struct = _can_use_instruction_struct_helper(); constexpr std::size_t SegPtrSize = 20, SegNumSize = 12, FullPtrSize = SegPtrSize + SegNumSize; constexpr std::size_t Ki = 1<<10, //Kibi Mi = Ki * Ki, //Mibi Gi = Mi * Mi; //Gibi constexpr std::size_t Segments = 1<; namespace Perms { enum class Perm : i64 {}; constexpr const Perm //No permissions: page is not usable at all unallocated{0}, none{0}, //Page may be read from read{1}, //Page may be written to write{2}, //Page may be executed from exec{4}, //Page is not visible to normal code (overrides read and write) priv{8}; inline Perm operator|(Perm l, Perm r) { return static_cast( static_cast(l) | static_cast(r) ); } inline Perm operator&(Perm l, Perm r) { return static_cast( static_cast(l) & static_cast(r) ); } inline Perm operator^(Perm l, Perm r) { return static_cast( static_cast(l) ^ static_cast(r) ); } inline Perm operator*(Perm p, bool b) { return b ? p : none; } inline Perm operator*(bool b, Perm p) { return b ? p : none; } } struct MMUentry { Perms::Perm perms=Perms::unallocated; std::unique_ptr page; MMUentry() = default; MMUentry(Perms::Perm p) : perms(p), page(std::make_unique()) {} }; class MMU { public: constexpr static i32 max_pages = Segments; MMU(bool selfmod = false) { //text segment: 16k words /**** Layout for text segment: **** * 0-15: reserved * 16-31: Special input register alias addresses * 32-1023: symbols (1-2W each; 1-8 or 9-16 characters) * 1024-2047: Input register alias addresses * 2048-16383: strings/data ROM ****/ memory[0] = MMUentry(Perms::read); // Code/scratch segment: 128k words memory[4] = MMUentry(Perms::read | Perms::write | Perms::exec); // Call stack segment: 8k words memory[35] = MMUentry(Perms::read | (Perms::write * selfmod) | Perms::priv); // Data stack segment: 864k words memory[36] = MMUentry(Perms::read | Perms::write); // High data stack: grows downward toward data stack memory[max_pages-5] = MMUentry(Perms::read | Perms::write); // Builtin code segment: 16k words memory[max_pages-4] = MMUentry(Perms::read | Perms::exec); memory[max_pages-3] = MMUentry(Perms::read | Perms::exec); memory[max_pages-2] = MMUentry(Perms::read | Perms::exec); memory[max_pages-1] = MMUentry(Perms::read | Perms::exec); } private: std::array memory = {}; }; class CPU { public: private: }; std::vector assemble(const std::string& prog); } /*stack s; stack hs; int arg; int gp0; int gp1; volatile int zero; void infix() { void push_out() { s.rotate(arg, 1); --arg; } void push_op() { s.pop(gp0); hs.push(gp0); ++gp1; } void pop_op() { hs.pop(gp0); --gp1; s.push(gp0); push_out(); } hs.push(gp0); hs.push(gp1); hs.push(arg); gp1 = 0; if (!arg) throw "Not enough arguments provided."; loop: if (is_operator()) goto op; if (iseq('(')) goto pushop; if (iseq(')')) goto rbrack; //number push_out(); goto check; op: if (iseq('(')) goto pushop; if (prec(s) > prec(hs)) goto pushop; if (prec(s) != prec(hs)) goto skip; if (iseq(hs, '^')) goto pushop; skip: pop_op(); goto op; pushop: push_op(); goto check; rbrack: if (iseq(hs, '(')) goto pop_brack; pop_op(); goto rbrack; pop_brack: hs.pop(zero); --gp1; check: if (arg) goto loop; cleanup: if (gp1 == 0) goto done; pop_op(); goto cleanup; done: hs.pop(arg); hs.pop(gp1); hs.pop(gp0); return; void push_out() { s.rotate(arg, 1); --arg; } void push_op() { s.pop(gp0); hs.push(gp0); ++gp1; } void pop_op() { hs.pop(gp0); --gp1; s.push(gp0); push_out(); } hs.push(gp0); hs.push(gp1); hs.push(arg); gp1 = 0; if (!arg) throw "Not enough arguments provided."; while (arg) { if (is_operator(s)) { while ( top(hs) != "(" && (prec(hs) > prec(s) || (prec(hs) == prec(s) && assoc(hs) == left)) ) { pop_op(); } s.pop(gp0); hs.push(gp0); ++gp1; } if (iseq(s, "(")) { push_op(); } if (iseq(s, ")")) { while (!iseq(hs, "(")) { pop_op(); } hs.pop(zero); --gp1; } if (is_number(s)) { push_out(); } } while (gp1) { pop_op(); } hs.pop(arg); hs.pop(gp1); hs.pop(gp0); return; }*/ #endif //_ASMVM_H_INCLUDED_