From 9f0127c3c82203d308e4230a4b32304e155d05c7 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Thu, 23 Feb 2023 18:04:49 -0500 Subject: [PATCH] fix cell size handling; optimize for speed --- Makefile | 3 + core.fth | 20 +-- corewords.cpp | 408 +++++++++++++++++++++---------------------------- corewords.hpp | 52 +------ dictionary.cpp | 5 +- parser.cpp | 17 ++- state.cpp | 64 +------- state.hpp | 74 ++++++--- 8 files changed, 258 insertions(+), 385 deletions(-) diff --git a/Makefile b/Makefile index 94d425d..560defa 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,9 @@ all: $(EXEFILE) small: CXXFLAGS += -Os small: $(EXEFILE) +fast: CXXFLAGS += -O3 -march=native -mtune=native +fast: $(EXEFILE) + $(EXEFILE): $(LIBFILE) $(LIBFILE): $(OBJFILES) diff --git a/core.fth b/core.fth index 901d9b9..4f7ef81 100644 --- a/core.fth +++ b/core.fth @@ -1,14 +1,16 @@ +: cell+ 2 + ; +: cells 2 * ; + + : . 0 sys ; : emit 1 sys ; : 1+ 1 + ; : 1- 1 - ; -: ! 2 _! ; -: @ 2 _@ ; -: , here ! 2 allot ; -: cell+ 2 + ; -: cells 2 * ; +: ! 1 _! ; +: @ 1 _@ ; +: , here ! 1 cells allot ; : over 1 pick ; : rot >r swap r> swap ; @@ -21,8 +23,8 @@ : 2over 3 pick 3 pick ; : 2swap rot >r rot r> ; -: c! 1 _! ; -: c@ 1 _@ ; +: c! 0 _! ; +: c@ 0 _@ ; : c, here c! 1 allot ; : char+ 1+ ; : chars ; @@ -77,8 +79,8 @@ : i postpone r@ ; imm : j postpone 2r> postpone r@ ['] -rot , postpone 2>r ; imm -: align here 1 & if 1 allot then ; -: aligned dup 1 & if 1+ then ; +: align here 1 cells 1- tuck & if 1 cells swap - allot else drop then ; +: aligned dup 1 cells 1- tuck & if 1 cells swap - allot else drop then ; : and & ; : or | ; diff --git a/corewords.cpp b/corewords.cpp index 9c52c8d..64708e9 100644 --- a/corewords.cpp +++ b/corewords.cpp @@ -18,241 +18,185 @@ #include "corewords.hpp" -Func CoreWords::get(int index) -{ - static const Func ops[WordCount] = { - op_drop, op_dup, op_swap, op_pick, op_sys, - op_add, op_sub, op_mul, op_div, op_mod, - /*10*/ op_peek, op_poke, op_pushr, op_popr, op_eq, - op_lt, op_allot, op_and, op_or, op_xor, - /*20*/ op_shl, op_shr, op_colon, op_semic, op_here, - op_depth, op_key, op_exit, op_tick, op_execute, - /*30*/ op_jmp, op_jmp0, op_lit, op_literal, op_rdepth +void CoreWords::run(unsigned int index, State& state) +{ + auto getword = [&state] { + auto word = state.dict.input(); + while (word.size() == 0) { + state.input(state); + word = state.dict.input(); + } + return word; + }; + auto newdef = [](Dictionary& dict, Word word) { + auto addr = dict.alignhere(); + dict.addDefinition(word); + dict.write(addr, + (dict.read(addr) & 0x1F) | + ((addr - dict.latest()) << 6)); + dict.latest(addr); + }; + auto tick = [&state](Word word) { + if (auto j = state.dict.find(word); j > 0) + state.push(state.dict.getexec(j)); + else if (auto i = CoreWords::findi(state, word); i >= 0) + state.push(i & ~CoreWords::Compiletime); + else + state.push(0); }; - return index >= 0 && index < WordCount ? ops[index] : nullptr; -} - -void CoreWords::op_drop(State& state) -{ - state.pop(); -} - -void CoreWords::op_dup(State& state) -{ - state.push(state.top()); -} - -void CoreWords::op_swap(State& state) -{ - std::swap(state.top(), state.pick(1)); -} - -void CoreWords::op_pick(State& state) -{ - state.push(state.pick(state.pop())); -} - -void CoreWords::op_sys(State& state) -{ - return user_sys(state); -} - -void CoreWords::op_add(State& state) -{ - const auto a = state.pop(); - state.top() += a; -} - -void CoreWords::op_sub(State& state) -{ - const auto a = state.pop(); - state.top() -= a; -} - -void CoreWords::op_mul(State& state) { - const auto a = state.pop(); - state.top() *= a; -} - -void CoreWords::op_div(State& state) { - const auto a = state.pop(); - state.top() /= a; -} - -void CoreWords::op_mod(State& state) { - const auto a = state.pop(); - state.top() %= a; -} - -void CoreWords::op_peek(State& state) { - if (auto w = state.pop(); w == 1) - state.push(state.dict.readbyte(state.pop())); - else - state.push(state.dict.read(state.pop())); -} - -void CoreWords::op_poke(State& state) { - const auto w = state.pop(); - const auto addr = state.pop(); - if (w == 1) - state.dict.writebyte(addr, state.pop()); - else - state.dict.write(addr, state.pop()); -} - -void CoreWords::op_pushr(State& state) { - state.pushr(state.pop()); -} - -void CoreWords::op_popr(State& state) { - state.push(state.popr()); -} - -void CoreWords::op_eq(State& state) { - const auto a = state.pop(); - state.top() = state.top() == a; -} - -void CoreWords::op_lt(State& state) { - const auto a = state.pop(); - state.top() = state.top() < a; -} - -void CoreWords::op_allot(State& state) { - state.dict.allot(state.pop()); -} - -void CoreWords::op_and(State& state) { - const auto a = state.pop(); - state.top() &= a; -} - -void CoreWords::op_or(State& state) { - const auto a = state.pop(); - state.top() |= a; -} - -void CoreWords::op_xor(State& state) { - const auto a = state.pop(); - state.top() ^= a; -} - -void CoreWords::op_shl(State& state) { - const auto a = state.pop(); - state.top() <<= a; -} - -void CoreWords::op_shr(State& state) { - const auto a = state.pop(); - state.top() >>= a; -} - -void CoreWords::op_colon(State& state) { - Word word = state.dict.input(); - while (word.size() == 0) { - state.input(state); - word = state.dict.input(); - } - - const auto start = state.dict.alignhere(); - state.dict.addDefinition(word); - state.dict.write(start, - (state.dict.read(start) & 0x1F) | - ((start - state.dict.latest()) << 6)); - state.dict.latest(start); - state.compiling(true); -} - -void CoreWords::op_tick(State& state) { - Word word = state.dict.input(); - while (word.size() == 0) { - state.input(state); - word = state.dict.input(); - } - - Cell xt = 0; - if (auto i = CoreWords::findi(state, word); i >= 0) { - xt = i & ~CoreWords::Compiletime; - } else if (auto j = state.dict.find(word); j > 0) { - xt = state.dict.getexec(j); - } - - state.push(xt); -} - -void CoreWords::op_execute(State& state) { - state.execute(state.pop()); -} - -void CoreWords::op_exit(State& state) { - state.ip = state.popr(); -} - -void CoreWords::op_semic(State& state) { - if (state.compiling()) { + Cell cell; + + switch (index) { + default: + // must be calling a defined subroutine + state.pushr(state.ip); + state.ip = index - sizeof(Cell); + break; + case 0: // drop + state.pop(); + break; + case 1: // dup + state.push(state.top()); + break; + case 2: // swap + std::swap(state.top(), state.pick(1)); + break; + case 3: // pick + state.push(state.pick(state.pop())); + break; + case 4: // sys + user_sys(state); + break; + case 5: // add + cell = state.pop(); + state.top() += cell; + break; + case 6: // sub + cell = state.pop(); + state.top() -= cell; + break; + case 7: // mul + cell = state.pop(); + state.top() *= cell; + break; + case 8: // div + cell = state.pop(); + state.top() /= cell; + break; + case 9: // mod + cell = state.pop(); + state.top() %= cell; + break; + case 10: // peek + if (state.pop()) + state.push(state.dict.read(state.pop())); + else + state.push(state.dict.readbyte(state.pop())); + break; + case 11: // poke + cell = state.pop(); + if (auto addr = state.pop(); cell) + state.dict.write(addr, state.pop()); + else + state.dict.writebyte(addr, state.pop()); + break; + case 12: // pushr + state.pushr(state.pop()); + break; + case 13: // popr + state.push(state.popr()); + break; + case 14: // equal + cell = state.pop(); + state.top() = state.top() == cell; + break; + case 15: // lt + cell = state.pop(); + state.top() = state.top() < cell; + break; + case 16: // allot + state.dict.allot(state.pop()); + break; + case 17: // and + cell = state.pop(); + state.top() &= cell; + break; + case 18: // or + cell = state.pop(); + state.top() |= cell; + break; + case 19: // xor + cell = state.pop(); + state.top() ^= cell; + break; + case 20: // shl + cell = state.pop(); + state.top() <<= cell; + break; + case 21: // shr + cell = state.pop(); + state.top() >>= cell; + break; + case 22: // colon + newdef(state.dict, getword()); + state.compiling(true); + break; + case 23: // tick + tick(getword()); + break; + case 24: // execute + state.execute(state.pop()); + break; + case 25: // exit + state.ip = state.popr(); + break; + case 26: // semic state.dict.add(findi("exit")); state.compiling(false); - } -} - -void CoreWords::op_here(State& state) { - state.push(state.dict.here); -} - -void CoreWords::op_lit(State& state) -{ - state.push(state.beyondip()); - state.ip += sizeof(Cell); -} - -void CoreWords::op_literal(State& state) -{ - if (state.compiling()) { + break; + case 27: // here + state.push(state.dict.here); + break; + case 28: // _lit + state.push(state.beyondip()); + break; + case 29: // literal state.dict.add(findi("_lit")); state.dict.add(state.pop()); + break; + case 30: // _jmp + state.ip = state.beyondip() - sizeof(Cell); + break; + case 31: // _jmp0 + if (state.pop()) + state.beyondip(); + else + state.ip = state.beyondip() - sizeof(Cell); + break; + case 32: // depth + state.push(state.size()); + break; + case 33: // _rdepth + state.push(state.rsize()); + break; + case 34: // key + cell = state.dict.read(Dictionary::Input); + while (cell <= 0) { + state.input(state); + cell = state.dict.read(Dictionary::Input); + } + + state.dict.write(Dictionary::Input, cell - 1); + + state.push( + state.dict.readbyte( + Dictionary::Input + sizeof(Cell) + + Dictionary::InputCells - cell)); + break; } } -void CoreWords::op_jmp(State& state) -{ - state.ip = state.beyondip() - sizeof(Cell); -} - -void CoreWords::op_jmp0(State& state) -{ - if (state.pop()) - state.ip += sizeof(Cell); - else - op_jmp(state); -} - -void CoreWords::op_depth(State& state) -{ - state.push(state.size()); -} - -void CoreWords::op_rdepth(State& state) -{ - state.push(state.rsize()); -} - -void CoreWords::op_key(State& state) -{ - auto len = state.dict.read(Dictionary::Input); - while (len <= 0) { - state.input(state); - len = state.dict.read(Dictionary::Input); - } - - state.dict.write(Dictionary::Input, len - 1); - Addr addr = Dictionary::Input + sizeof(Cell) + - Dictionary::InputCells - len; - Cell val = state.dict.readbyte(addr); - - state.push(val); -} - int CoreWords::findi(std::string_view word) { std::size_t i; @@ -293,15 +237,3 @@ int CoreWords::findi(State& state, Word word) return -1; } -Func CoreWords::find(State& state, Word word) -{ - const auto i = findi(state, word); - return i >= 0 ? get(i & ~Compiletime) : nullptr; -} - -void CoreWords::run(int i, State& state) -{ - if (i >= 0 && i < WordCount) - get(i)(state); -} - diff --git a/corewords.hpp b/corewords.hpp index ce5bba0..6f982a0 100644 --- a/corewords.hpp +++ b/corewords.hpp @@ -36,8 +36,7 @@ public: static int findi(std::string_view); static int findi(State&, Word); - static Func find(State&, Word); - static void run(int, State&); + static void run(unsigned int, State&); private: // Ends with '\0': regular word @@ -45,50 +44,11 @@ private: constexpr static char wordsarr[] = "drop\0dup\0swap\0pick\0sys\0" "+\0-\0*\0/\0%\0" - "_@\0_!\0>r\0r>\0" - "=\0<\0allot\0&\0|\0" - "^\0<<\0>>\0:\1" - ";\1here\0depth\0" - "key\0exit\0'\0execute\0_jmp\0" - "_jmp0\0_lit\0literal\1_rdepth\0"; - - static Func get(int); - - static void op_drop(State&); - static void op_dup(State&); - static void op_swap(State&); - static void op_pick(State&); - static void op_sys(State&); - static void op_add(State&); - static void op_sub(State&); - static void op_mul(State&); - static void op_div(State&); - static void op_mod(State&); - static void op_peek(State&); - static void op_poke(State&); - static void op_pushr(State&); - static void op_popr(State&); - static void op_eq(State&); - static void op_lt(State&); - static void op_allot(State&); - static void op_and(State&); - static void op_or(State&); - static void op_xor(State&); - static void op_shl(State&); - static void op_shr(State&); - static void op_colon(State&); - static void op_semic(State&); - static void op_here(State&); - static void op_lit(State&); - static void op_depth(State&); - static void op_rdepth(State&); - static void op_key(State&); - static void op_exit(State&); - static void op_tick(State&); - static void op_execute(State&); - static void op_jmp(State&); - static void op_jmp0(State&); - static void op_literal(State&); + "_@\0_!\0>r\0r>\0=\0" + "<\0allot\0&\0|\0^\0" + "<<\0>>\0:\0'\0execute\0" + "exit\0;\1here\0_lit\0literal\1" + "_jmp\0_jmp0\0depth\0_rdepth\0key\0"; }; #endif // ALEEFORTH_COREWORDS_HPP diff --git a/dictionary.cpp b/dictionary.cpp index 2ba6f88..de10303 100644 --- a/dictionary.cpp +++ b/dictionary.cpp @@ -34,8 +34,9 @@ void Dictionary::add(Cell value) Addr Dictionary::aligned(Addr addr) const noexcept { - if (addr & (sizeof(Cell) - sizeof(uint8_t))) - addr = (addr + sizeof(Cell)) & ~(sizeof(Cell) - sizeof(uint8_t)); + auto unaligned = addr & (sizeof(Cell) - sizeof(uint8_t)); + if (unaligned) + addr += sizeof(Cell) - unaligned; return addr; } diff --git a/parser.cpp b/parser.cpp index 8a77df5..0883230 100644 --- a/parser.cpp +++ b/parser.cpp @@ -54,19 +54,20 @@ ParseStatus Parser::parseWord(State& state, Word word) { int ins, imm; - ins = CoreWords::findi(state, word); - if (ins < 0) { - ins = state.dict.find(word); + ins = state.dict.find(word); - if (ins <= 0) { + if (ins <= 0) { + ins = CoreWords::findi(state, word); + + if (ins < 0) { return parseNumber(state, word); } else { - imm = state.dict.read(ins) & CoreWords::Immediate; - ins = state.dict.getexec(ins); + imm = ins & CoreWords::Compiletime; + ins &= ~CoreWords::Compiletime; } } else { - imm = ins & CoreWords::Compiletime; - ins &= ~CoreWords::Compiletime; + imm = state.dict.read(ins) & CoreWords::Immediate; + ins = state.dict.getexec(ins); } if (state.dict.read(Dictionary::Postpone)) { diff --git a/state.cpp b/state.cpp index 16a573e..c371101 100644 --- a/state.cpp +++ b/state.cpp @@ -21,13 +21,6 @@ #include -struct pop {}; -struct push {}; -struct popr {}; -struct pushr {}; -struct top {}; -struct pick {}; - bool State::compiling() const { return dict.read(Dictionary::Compiling); @@ -41,7 +34,6 @@ void State::compiling(bool yes) void State::execute(Addr addr) { if (addr < CoreWords::WordCount) { - // Must be a core-word CoreWords::run(addr, *this); } else { pushr(0); @@ -49,65 +41,11 @@ void State::execute(Addr addr) do { ip += sizeof(Cell); - - const auto ins = dict.read(ip); - if (ins < CoreWords::WordCount) { - CoreWords::run(ins, *this); - } else { - pushr(ip); - ip = ins - sizeof(Cell); - } + CoreWords::run(dict.read(ip), *this); } while (ip); } } -Cell State::beyondip() const -{ - return dict.read(ip + sizeof(Cell)); -} - -void State::pushr(Cell value) -{ - if (rsize() == ReturnStackSize) - throw ::pushr(); - *++rsp = value; -} - -Cell State::popr() -{ - if (rsize() == 0) - throw ::popr(); - return *rsp--; -} - -void State::push(Cell value) -{ - if (size() == DataStackSize) - throw ::push(); - *++dsp = value; -} - -Cell State::pop() -{ - if (size() == 0) - throw ::pop(); - return *dsp--; -} - -Cell& State::top() -{ - if (size() == 0) - throw ::top(); - return *dsp; -} - -Cell& State::pick(std::size_t i) -{ - if (i >= size()) - throw ::pick(); - return *(dsp - i); -} - std::size_t State::size() const noexcept { return std::distance(dstack, static_cast(dsp)) + 1; diff --git a/state.hpp b/state.hpp index 73bd8eb..279aefd 100644 --- a/state.hpp +++ b/state.hpp @@ -24,21 +24,20 @@ #include -constexpr unsigned DataStackSize = 12; -constexpr unsigned ReturnStackSize = 12; +constexpr unsigned DataStackSize = 8; +constexpr unsigned ReturnStackSize = 8; -class State +struct State { + Addr ip = 0; + Dictionary& dict; + void (*input)(State&); + Cell dstack[DataStackSize] = {}; Cell rstack[ReturnStackSize] = {}; Cell *dsp = dstack - 1; Cell *rsp = rstack - 1; -public: - Addr ip = 0; - Dictionary& dict; - void (*input)(State&); - constexpr State(Dictionary& d, void (*i)(State&)): dict(d), input(i) {} @@ -47,19 +46,56 @@ public: void execute(Addr); - Cell beyondip() const; - - void pushr(Cell); - Cell popr(); - - void push(Cell); - Cell pop(); - - Cell& top(); - Cell& pick(std::size_t); - std::size_t size() const noexcept; std::size_t rsize() const noexcept; + + inline void push(Cell value) { + if (dsp == dstack + DataStackSize - 1) + throw exc_push(); + *++dsp = value; + } + + inline Cell pop() { + if (dsp < dstack) + throw exc_pop(); + return *dsp--; + } + + inline Cell beyondip() { + ip += sizeof(Cell); + return dict.read(ip); + } + + inline void pushr(Cell value) { + if (rsp == rstack + ReturnStackSize - 1) + throw exc_pushr(); + *++rsp = value; + } + + inline Cell popr() { + if (rsp < rstack) + throw exc_popr(); + return *rsp--; + } + + inline Cell& top() { + if (dsp < dstack) + throw exc_top(); + return *dsp; + } + + inline Cell& pick(std::size_t i) { + if (dsp - i < dstack) + throw exc_pick(); + return *(dsp - i); + } + + struct exc_pop {}; + struct exc_push {}; + struct exc_popr {}; + struct exc_pushr {}; + struct exc_top {}; + struct exc_pick {}; }; #endif // ALEEFORTH_STATE_HPP