From bbaf58c9fd0f485266d86868dc35f1d2be3589cd Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sun, 26 Jun 2022 16:24:13 -0700 Subject: Significant changes, and a working "ISA" that just computes fib(n). --- Makefile | 29 ++++-- aisa/aisa.h | 52 +++++++++- aisa/async.h | 225 ++++++++++++++++++++++++++++++++++++++++ aisa/eval.h | 65 ------------ aisa/simple-models.h | 95 +++++++++++++++++ isa/fib/fib.h | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 135 ++++++++++++++---------- tools/iwyu.imp | 3 + 8 files changed, 759 insertions(+), 133 deletions(-) create mode 100644 aisa/async.h delete mode 100644 aisa/eval.h create mode 100644 aisa/simple-models.h create mode 100644 isa/fib/fib.h create mode 100644 tools/iwyu.imp diff --git a/Makefile b/Makefile index 9e84cc8..ed96817 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,11 @@ CXX ?= g++ IWYU ?= iwyu CHRONIC ?= chronic -CXXFLAGS := -Wall -Werror -std=c++20 -fPIC -iquote . ${OPTIMIZE} ${DEBUG} +PKGS := fmt +PKG_FLAGS := $(shell pkg-config --cflags ${PKGS}) +PKG_LIBS := -Wl,--push-state,--as-needed $(shell pkg-config --libs ${PKGS}) -Wl,--pop-state + +CXXFLAGS := -Wall -Werror -std=c++20 -fPIC -iquote . ${PKG_FLAGS} ${OPTIMIZE} ${DEBUG} .DEFAULT_GOAL := all @@ -24,7 +28,7 @@ endef export GITTAGCPP ifneq ($(shell which ${IWYU}),) -iwyu = ${CHRONIC} ${IWYU} -Xiwyu --error ${CXXFLAGS} $(1) +iwyu = ${CHRONIC} ${IWYU} -Xiwyu --error -Xiwyu --mapping_file=tools/iwyu.imp ${CXXFLAGS} $(1) else $(warning Not using IWYU) iwyu = @@ -42,29 +46,32 @@ $(call libname,$(1).a): $(patsubst %.cpp,build/%.o,$(wildcard $(1)/*.cpp)) $(call libname,$(1).so): $(patsubst %.cpp,build/%.o,$(wildcard $(1)/*.cpp)) @mkdir -p $$(dir $$@) - $${CXX} $${CXXFLAGS} -shared -o $$@ $$+ + $${CXX} $${CXXFLAGS} -shared -o $$@ $$+ ${PKG_LIBS} PARTARS += $(call libname,$(1).a) PARTSOS += $(call libname,$(1).so) -else +endif -$(call libname,$(1).cpp): +ifdef iwyu + +build/$(1)/iwyu.cpp: @mkdir -p $$(dir $$@) @tools/iwyu-header $$(wildcard $(1)/*.h) > $$@ @$$(call iwyu,$$@) -.PHONY: $(call libname,$(1).cpp) +.PHONY: build/$(1)/iwyu.cpp -EXTRA_TARGETS += $(call libname,$(1).cpp) +IWYU_CPPS += build/$(1)/iwyu.cpp endif endef PARTS := $(patsubst ./%,%,$(shell find -mindepth 1 -type d -\( -name .\* -prune -o -name build -prune -o -name tools -prune -o -print -\))) + PARTARS := PARTSOS := -EXTRA_TARGETS := +IWYU_CPPS := $(foreach part,${PARTS},$(eval $(call mklib,${part}))) @@ -73,7 +80,7 @@ MAINOBJS += build/git-tag.o $(info ) -all: ${EXTRA_TARGETS} issim issim-static +all: ${IWYU_CPPS} issim issim-static issim: build/issim-dynamic @ln -sf $< $@ @@ -85,11 +92,11 @@ issim-static: build/issim-static build/issim-dynamic: ${MAINOBJS} ${PARTSOS} @mkdir -p $(dir $@) - ${CXX} ${CXXFLAGS} -o $@ $+ + ${CXX} ${CXXFLAGS} -o $@ $+ ${PKG_LIBS} build/issim-static: ${MAINOBJS} ${PARTARS} @mkdir -p $(dir $@) - ${CXX} ${CXXFLAGS} -o $@ $+ + ${CXX} ${CXXFLAGS} -o $@ $+ ${PKG_LIBS} clean: rm -rf build issim issim-static diff --git a/aisa/aisa.h b/aisa/aisa.h index 3c260c1..4488529 100644 --- a/aisa/aisa.h +++ b/aisa/aisa.h @@ -1,20 +1,67 @@ #pragma once #include +#include #include +#include #include #include namespace aisa { + using addr_t = std::uint64_t; + using byte_t = std::uint8_t; using regnum_t = std::uint_fast64_t; using regval_t = std::uint64_t; + struct Task; + + struct ISA { + virtual ~ISA() { } + + virtual std::pair, regval_t> initial_task() const = 0; + }; + + struct Step; + + struct Task { + regnum_t environment; + + virtual ~Task() { } + + virtual std::string disasm() const = 0; + + virtual std::optional, regval_t>> step(regval_t environment_val) const { return {}; } + }; + + struct MemInfo { + addr_t physical_addr; + addr_t size; + }; + + struct Wires { + std::vector source_vals; + std::vector memory_val; + bool aborted = false; + std::vector destination_vals; + std::optional, regval_t>> new_task; + }; + + enum class MOp { + NONE, + LOAD, + STORE, + }; + struct Step { std::optional> predicate; std::vector source_regs; std::vector destination_regs; + virtual ~Step() { } + + virtual std::string disasm(const Wires *w = nullptr) const = 0; + std::optional predicate_reg() const { if (predicate.has_value()) @@ -29,7 +76,10 @@ namespace aisa { return {}; } - virtual std::vector compute_destinations(const std::vector &source_vals) const = 0; + MOp mop = MOp::NONE; + + virtual MemInfo meminfo(const Wires &wires) const { return {}; } + virtual void evaluate(Wires &wires) const { }; }; } diff --git a/aisa/async.h b/aisa/async.h new file mode 100644 index 0000000..42e99e7 --- /dev/null +++ b/aisa/async.h @@ -0,0 +1,225 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "aisa/aisa.h" +#include "aisa/coroutine.h" // IWYU pragma: export + +namespace aisa { + + template struct AsyncEval { + CRTP & crtp() noexcept { return static_cast(*this); } + + task async_load_reg(regnum_t rn) + { + while (true) { + if (auto rv = crtp().load_reg(rn); rv.has_value()) + co_return *rv; + co_await std::suspend_always{}; + } + } + + task async_store_reg(regnum_t rn, regval_t rv) + { + while (true) { + if (crtp().store_reg(rn, rv)) + co_return; + co_await std::suspend_always{}; + } + } + + task async_fetch_mem(byte_t *bytes, addr_t physical_addr, addr_t size) + { + while (true) { + if (crtp().fetch_mem(bytes, physical_addr, size)) + co_return; + co_await std::suspend_always{}; + } + } + + task async_store_mem(addr_t physical_addr, const byte_t *bytes, addr_t size) + { + while (true) { + if (crtp().store_mem(physical_addr, bytes, size)) + co_return; + co_await std::suspend_always{}; + } + } + + task async_predicate(const Step &step) + { + if (step.predicate.has_value()) { + regval_t pval = co_await crtp().async_load_reg(step.predicate->first); + co_return pval == step.predicate->second; + } + co_return true; + } + + task async_load_source_registers(const Step &step, Wires &w) + { + w.source_vals.resize(step.source_regs.size()); + for (unsigned int i = 0; i < step.source_regs.size(); ++i) + w.source_vals[i] = co_await crtp().async_load_reg(step.source_regs[i]); + } + + task async_load_source_memory(const Step &step, const MemInfo &mi, Wires &w) + { + w.memory_val.resize(mi.size); + co_await crtp().async_fetch_mem(w.memory_val.data(), mi.physical_addr, mi.size); + } + + task async_load_sources(const Step &step, Wires &w) + { + co_await crtp().async_load_source_registers(step, w); + + if (step.mop == MOp::LOAD) { + auto mi = step.meminfo(w); + co_await crtp().async_load_source_memory(step, mi, w); + } + } + + task async_write_destination_registers(const Step &step, const Wires &w) + { + for (unsigned int i = 0; i < step.destination_regs.size(); ++i) + co_await crtp().async_store_reg(step.destination_regs[i], w.destination_vals[i]); + } + + task async_write_destination_memory(const Step &step, const MemInfo &mi, const Wires &w) + { + co_await crtp().async_store_mem(mi.physical_addr, w.memory_val.data(), mi.size); + } + + task async_write_destinations(const Step &step, const Wires &w) + { + if (w.aborted) + co_return; + + co_await crtp().async_write_destination_registers(step, w); + + if (step.mop == MOp::STORE) { + auto mi = step.meminfo(w); + co_await crtp().async_write_destination_memory(step, mi, w); + } + } + + task async_push_task(std::unique_ptr &&task) + { + while (true) { + if (crtp().push_task(std::move(task))) + co_return; + co_await std::suspend_always{}; + } + } + + task async_new_task(std::unique_ptr &&task, regval_t environment_val) + { + auto rn = task->environment; + co_await crtp().async_push_task(std::move(task)); + co_await crtp().async_store_reg(rn, environment_val); + } + + task async_run_step(const Step &step) + { + Wires w; + + if (!co_await crtp().async_predicate(step)) + co_return std::move(w); + + co_await crtp().async_load_sources(step, w); + + step.evaluate(w); + + co_await crtp().async_write_destinations(step, w); + + if (w.new_task.has_value()) + co_await crtp().async_new_task(std::move(w.new_task->first), w.new_task->second); + + co_return std::move(w); + } + + task async_top_task() + { + while (true) { + if (auto rv = crtp().top_task(); rv.has_value()) + co_return &**rv; + co_await std::suspend_always{}; + } + } + + task async_pop_task() + { + while (true) { + if (crtp().pop_task()) + co_return; + co_await std::suspend_always{}; + } + } + + task>> async_fetch_step() + { + auto task = co_await crtp().async_top_task(); + + auto rn = task->environment; + auto rv = co_await crtp().async_load_reg(rn); + + auto step = task->step(rv); + if (step.has_value()) { + co_await crtp().async_store_reg(rn, step->second); + co_return std::move(step->first); + } else { + co_await crtp().async_pop_task(); + co_return {}; + } + } + + task, Wires>> async_fetch_and_run_step() + { + while (true) { + if (auto step = co_await crtp().async_fetch_step(); step.has_value()) { + auto wires = co_await crtp().async_run_step(**step); + co_return {std::move(*step), std::move(wires)}; + } + } + } + + task async_run_subtree() + { + while (true) { + if (auto step = co_await crtp().async_fetch_step(); step.has_value()) + co_await crtp().async_run_step_and_subtree(**step); + else + break; + } + } + + task async_run_step_and_subtree(const Step &step) + { + auto w = co_await crtp().async_run_step(step); + + if (w.new_task.has_value()) + co_await crtp().async_run_subtree(); + + co_return std::move(w); + } + + task async_setup_initial_task(const ISA &isa) + { + auto task = isa.initial_task(); + + co_await crtp().async_new_task(std::move(task.first), task.second); + } + + task async_run(const ISA &isa) + { + co_await crtp().async_setup_initial_task(isa); + + co_await crtp().async_run_subtree(); + } + + }; + +} diff --git a/aisa/eval.h b/aisa/eval.h deleted file mode 100644 index a301e93..0000000 --- a/aisa/eval.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "aisa/aisa.h" -#include "aisa/coroutine.h" // IWYU pragma: export - -namespace aisa { - - template struct EvalState { - struct EvalContext { - task coroutine; - - bool resume() { return coroutine(); } - }; - - CRTP & crtp() noexcept { return static_cast(*this); } - - task async_load_reg(regnum_t rn) - { - while (true) { - if (auto rv = crtp().load_reg(rn); rv.has_value()) - co_return *rv; - co_await std::suspend_always{}; - } - } - - task async_store_reg(regnum_t rn, regval_t rv) - { - while (true) { - if (crtp().store_reg(rn, rv)) - co_return; - co_await std::suspend_always{}; - } - } - - task async_evaluate(EvalContext &contex, const Step &step) - { - if (step.predicate.has_value()) { - regval_t pval = co_await async_load_reg(step.predicate->first); - if (pval != step.predicate->second) - co_return; - } - std::vector source_vals; - source_vals.reserve(step.source_regs.size()); - for (unsigned int i = 0; i < step.source_regs.size(); ++i) - source_vals.emplace_back(co_await async_load_reg(step.source_regs[i])); - auto destination_vals = step.compute_destinations(source_vals); - for (unsigned int i = 0; i < step.destination_regs.size(); ++i) - co_await async_store_reg(step.destination_regs[i], destination_vals[i]); - } - - std::unique_ptr operator()(const Step &step) - { - auto context = std::make_unique(); - context->coroutine = async_evaluate(*context, step); - return context; - } - }; - -} diff --git a/aisa/simple-models.h b/aisa/simple-models.h new file mode 100644 index 0000000..89e8752 --- /dev/null +++ b/aisa/simple-models.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aisa/aisa.h" + +namespace aisa { + + template struct PagedMem { + using page_t = std::array; + + static const addr_t PAGE_SIZE = 1 << PAGE_BITS; + static const addr_t PAGE_MASK = PAGE_SIZE - 1; + + std::map pages; + + bool fetch_mem(byte_t *bytes, addr_t addr, addr_t size) + { + if (size == 0) + return true; + auto page_base = addr >> PAGE_BITS; + auto page_offset = addr & PAGE_MASK; + auto size_here = std::min(size, PAGE_SIZE - page_offset); + if (auto page = pages.find(page_base); page != pages.end()) + std::memcpy(bytes, page->second.data() + page_offset, size_here); + else + std::memset(bytes, 0, size_here); + return fetch_mem(bytes + size_here, addr + size_here, size - size_here); + } + + bool store_mem(addr_t addr, const byte_t *bytes, addr_t size) + { + if (size == 0) + return true; + auto page_base = addr >> PAGE_BITS; + auto page_offset = addr & PAGE_MASK; + auto size_here = std::min(size, PAGE_SIZE - page_offset); + std::memcpy(pages[page_base].data() + page_offset, bytes, size_here); + return store_mem(addr + size_here, bytes + size_here, size - size_here); + } + }; + + struct TaskStack { + std::deque> tasks; + + bool pop_task() + { + if (tasks.empty()) + return false; + tasks.pop_back(); + return true; + } + + bool push_task(std::unique_ptr &&task) + { + tasks.emplace_back(std::move(task)); + return true; + } + + std::optional top_task() + { + if (tasks.empty()) + return {}; + return tasks.back().get(); + } + }; + + struct VectorRF { + std::vector> rf; + + std::optional load_reg(regnum_t rn) const + { + if (rf.size() <= rn) + return {}; + return rf[rn]; + } + + bool store_reg(regnum_t rn, regval_t rv) + { + if (rf.size() <= rn) + rf.resize(rn + 1); + rf[rn] = rv; + return true; + } + }; + +} diff --git a/isa/fib/fib.h b/isa/fib/fib.h new file mode 100644 index 0000000..13801c8 --- /dev/null +++ b/isa/fib/fib.h @@ -0,0 +1,288 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "aisa/aisa.h" + +namespace isa::fib { + + namespace Reg { + enum { + ENV_TOP, + ENV_FIB, + + AREG, + ATMP, + + PC, + + A, + B, + Q, + }; + + const char *disasm(aisa::regnum_t x) + { + switch (x) { + case ENV_TOP: return "ENV_TOP"; + case ENV_FIB: return "ENV_FIB"; + case AREG: return "AREG"; + case ATMP: return "ATMP"; + case PC: return "PC"; + case A: return "A"; + case B: return "B"; + case Q: return "Q"; + default: return "???"; + } + } + } + + struct StepAdd : public aisa::Step { + StepAdd(aisa::regnum_t q, aisa::regnum_t a, aisa::regnum_t b) + { + source_regs.resize(2); + source_regs[0] = a; + source_regs[1] = b; + + destination_regs.resize(1); + destination_regs[0] = q; + } + + std::string disasm(const aisa::Wires *w) const override + { + if (w) + return fmt::format("{}({}) <- {}({}) + {}({})", Reg::disasm(destination_regs[0]), w->destination_vals[0], Reg::disasm(source_regs[0]), w->source_vals[0], Reg::disasm(source_regs[1]), w->source_vals[1]); + return fmt::format("{} <- {} + {}", Reg::disasm(destination_regs[0]), Reg::disasm(source_regs[0]), Reg::disasm(source_regs[1])); + } + + void evaluate(aisa::Wires &w) const override + { + w.destination_vals.resize(1); + w.destination_vals[0] = w.source_vals[0] + w.source_vals[1]; + } + }; + + struct StepAddImmediate : public aisa::Step { + aisa::regval_t x; + + StepAddImmediate(aisa::regnum_t q, aisa::regnum_t a, aisa::regval_t x) + :x(x) + { + source_regs.resize(1); + source_regs[0] = a; + + destination_regs.resize(1); + destination_regs[0] = q; + } + + std::string disasm(const aisa::Wires *w) const override + { + if (w) + return fmt::format("{}({}) <- {}({}) + {}", Reg::disasm(destination_regs[0]), w->destination_vals[0], Reg::disasm(source_regs[0]), w->source_vals[0], x); + return fmt::format("{} <- {} + {}", Reg::disasm(destination_regs[0]), Reg::disasm(source_regs[0]), x); + } + + void evaluate(aisa::Wires &w) const override + { + w.destination_vals.resize(1); + w.destination_vals[0] = w.source_vals[0] + x; + } + }; + + template struct StepLoad : public aisa::Step { + StepLoad(aisa::regnum_t q, aisa::regnum_t a) + { + source_regs.resize(1); + source_regs[0] = a; + + destination_regs.resize(1); + destination_regs[0] = q; + + mop = aisa::MOp::LOAD; + } + + std::string disasm(const aisa::Wires *w) const override + { + if (w) + return fmt::format("{}({}) <- [{}({})]", Reg::disasm(destination_regs[0]), w->destination_vals[0], Reg::disasm(source_regs[0]), w->source_vals[0]); + return fmt::format("{} <- [{}]", Reg::disasm(destination_regs[0]), Reg::disasm(source_regs[0])); + } + + aisa::MemInfo meminfo(const aisa::Wires &w) const override + { + aisa::MemInfo mi; + mi.physical_addr = w.source_vals[0] * WORD; + mi.size = WORD; + return mi; + } + + void evaluate(aisa::Wires &w) const override + { + w.destination_vals.resize(1); + auto &q = w.destination_vals[0]; + q = 0; + for (unsigned int i = 0; i < WORD; ++i) + q |= static_cast(w.memory_val[i]) << (8 * i); + } + }; + + struct StepMove : public aisa::Step { + StepMove(aisa::regnum_t q, aisa::regnum_t a) + { + source_regs.resize(1); + source_regs[0] = a; + + destination_regs.resize(1); + destination_regs[0] = q; + } + + std::string disasm(const aisa::Wires *w) const override + { + if (w) + return fmt::format("{}({}) <- {}({})", Reg::disasm(destination_regs[0]), w->destination_vals[0], Reg::disasm(source_regs[0]), w->source_vals[0]); + return fmt::format("{} <- {}", Reg::disasm(destination_regs[0]), Reg::disasm(source_regs[0])); + } + + void evaluate(aisa::Wires &w) const override + { + w.destination_vals = w.source_vals; + } + }; + + struct StepMoveImmediate : public aisa::Step { + aisa::regval_t x; + + StepMoveImmediate(aisa::regnum_t q, aisa::regval_t x) + : x(x) + { + destination_regs.resize(1); + destination_regs[0] = q; + } + + std::string disasm(const aisa::Wires *w) const override + { + if (w) + return fmt::format("{}({}) <- {}", Reg::disasm(destination_regs[0]), w->destination_vals[0], x); + return fmt::format("{} <- {}", Reg::disasm(destination_regs[0]), x); + } + + void evaluate(aisa::Wires &w) const override + { + w.destination_vals.resize(1); + w.destination_vals[0] = x; + } + }; + + template struct StepSpawn : public aisa::Step { + void evaluate(aisa::Wires &w) const override + { + w.new_task = {std::make_unique(), 0}; + } + + std::string disasm(const aisa::Wires *w) const override + { + return fmt::format("spawn"); + } + }; + + template struct StepStore : public aisa::Step { + StepStore(aisa::regnum_t a, aisa::regnum_t d) + { + source_regs.resize(2); + source_regs[0] = a; + source_regs[1] = d; + + mop = aisa::MOp::STORE; + } + + std::string disasm(const aisa::Wires *w) const override + { + if (w) + return fmt::format("[{}({})] <- {}({})", Reg::disasm(source_regs[0]), w->source_vals[0], Reg::disasm(source_regs[1]), w->source_vals[1]); + return fmt::format("[{}] <- {}", Reg::disasm(source_regs[0]), Reg::disasm(source_regs[1])); + } + + aisa::MemInfo meminfo(const aisa::Wires &w) const override + { + aisa::MemInfo mi; + mi.physical_addr = w.source_vals[0] * WORD; + mi.size = WORD; + return mi; + } + + void evaluate(aisa::Wires &w) const override + { + w.memory_val.resize(WORD); + for (unsigned int i = 0; i < WORD; ++i) + w.memory_val[i] = w.source_vals[1] >> (8 * i); + } + }; + + template struct TaskFib : public aisa::Task { + TaskFib() + { + environment = Reg::ENV_FIB; + } + + std::string disasm() const override + { + return "fib"; + } + + std::optional, aisa::regval_t>> step(aisa::regval_t env) const override + { + switch (env) { + case 0: return {{std::make_unique>(Reg::A, Reg::PC), env+1}}; + case 1: return {{std::make_unique(Reg::PC, Reg::PC, 1), env+1}}; + case 2: return {{std::make_unique>(Reg::B, Reg::PC), env+1}}; + case 3: return {{std::make_unique(Reg::AREG, Reg::PC, 1), env+1}}; + case 4: return {{std::make_unique(Reg::Q, Reg::A, Reg::B), env+1}}; + case 5: return {{std::make_unique>(Reg::AREG, Reg::Q), env+1}}; + } + + return {}; + } + }; + + template struct TaskTop : public aisa::Task { + TaskTop() + { + environment = Reg::ENV_TOP; + } + + std::string disasm() const override + { + return "top"; + } + + std::optional, aisa::regval_t>> step(aisa::regval_t env) const override + { + switch (env) { + case 0: return {{std::make_unique(Reg::PC, 0), env+1}}; + case 1: return {{std::make_unique(Reg::AREG, 0), env+1}}; + case 2: return {{std::make_unique(Reg::ATMP, 0), env+1}}; + case 3: return {{std::make_unique>(Reg::AREG, Reg::ATMP), env+1}}; + case 4: return {{std::make_unique(Reg::AREG, 1), env+1}}; + case 5: return {{std::make_unique(Reg::ATMP, 1), env+1}}; + case 6: return {{std::make_unique>(Reg::AREG, Reg::ATMP), env+1}}; + case 7: return {{std::make_unique>>(), env}}; + } + + return {}; + } + }; + + template struct Fib : public aisa::ISA { + std::pair, aisa::regval_t> initial_task() const override + { + auto t = std::make_unique>(); + return {std::move(t), 0}; + } + }; + +} diff --git a/main.cpp b/main.cpp index e88d740..f172226 100644 --- a/main.cpp +++ b/main.cpp @@ -1,89 +1,112 @@ -#include +#include #include -#include #include #include #include -#include #include -#include #include "aisa/aisa.h" -#include "aisa/eval.h" +#include "aisa/async.h" +#include "aisa/simple-models.h" #include "git-tag.h" +#include "isa/fib/fib.h" + +const bool show_mem_fetch = false; +const bool show_mem_store = true; +const bool show_regs = false; +const bool show_steps = true; +const bool show_tasks = false; int main(int argc, const char *argv[]) { std::cout << "Version " << GIT_TAG << "\n"; - struct CopyStep : public aisa::Step { - CopyStep(std::pair pred, const std::initializer_list> ®s) + isa::fib::Fib<2> fib; + + struct Eval : public aisa::AsyncEval, aisa::PagedMem<>, aisa::TaskStack, aisa::VectorRF { + bool fetch_mem(aisa::byte_t *bytes, aisa::addr_t addr, aisa::addr_t size) { - predicate = std::move(pred); - source_regs.reserve(regs.size()); - destination_regs.reserve(regs.size()); - for (const auto &rp : regs) { - source_regs.emplace_back(rp.first); - destination_regs.emplace_back(rp.second); + if (aisa::PagedMem<>::fetch_mem(bytes, addr, size)) { + if (show_mem_fetch) { + fmt::print("\t\t\t"); + for (; size; --size) + fmt::print("{:02x} ", *bytes++); + fmt::print("= [{:x}]\n", addr); + } + return true; } + return false; } - - std::vector compute_destinations(const std::vector &source_vals) const override + bool store_mem(aisa::addr_t addr, const aisa::byte_t *bytes, aisa::addr_t size) { - return source_vals; + if (aisa::PagedMem<>::store_mem(addr, bytes, size)) { + if (show_mem_store) { + fmt::print("\t\t\t[{:x}] =", addr); + for (; size; --size) + fmt::print(" {:02x}", *bytes++); + fmt::print("\n"); + } + return true; + } + return false; } - } step{{123, 456}, {{1, 2}, {3, 4}, {5, 6}}}; - struct State : public aisa::EvalState { - std::map regs; + bool store_reg(aisa::regnum_t rn, aisa::regval_t rv) + { + if (aisa::VectorRF::store_reg(rn, rv)) { + if (show_regs) + fmt::print(".{} = {}\n", isa::fib::Reg::disasm(rn), rv); + return true; + } + return false; + } - std::optional load_reg(aisa::regnum_t rn) + bool push_task(std::unique_ptr &&task) { - std::cout << "state.load_reg(" << rn << ") = "; - if (auto x = regs.find(rn); x != regs.end()) { - std::cout << x->second << "\n"; - return x->second; + auto d = task->disasm(); + if (aisa::TaskStack::push_task(std::move(task))) { + if (show_tasks) + fmt::print("\t\t*** ENTER {} ***\n", d); + return true; } - std::cout << "(not available)\n"; - return {}; + return false; } - bool store_reg(aisa::regnum_t rn, aisa::regval_t rv) + bool pop_task() { - std::cout << "state.store_reg(" << rn << " <- " << rv << ")\n"; - regs[rn] = rv; - return true; + if (aisa::TaskStack::pop_task()) { + if (show_tasks) + fmt::print("\t\t *** LEAVE ***\n"); + return true; + } + return false; } - } state; + } eval; - auto t = state.async_load_reg(999); - std::cout << "run\n"; t(); - std::cout << "run\n"; t(); - std::cout << "run\n"; t(); - std::cout << "set regs[999] = 54321\n"; state.store_reg(999, 54321); - std::optional result; - while (!result.has_value()) { - std::cout << "run\n"; - result = t(); + if (!eval.async_setup_initial_task(fib)()) { + fmt::print("Failed to complete initial setup.\n"); + return 1; } - std::cout << "result = " << *result << "\n"; - std::cout << "\n\n\n"; + while (true) { + auto res = eval.async_fetch_and_run_step()(); + if (res.has_value()) { + auto &es = *res; + if (es.first) { + auto &step = *es.first; + auto &w = es.second; + if (show_steps) + fmt::print("\t{}\n", step.disasm(&w)); + } else { + break; + } + } else { + fmt::print("Failed to complete step.\n"); + return 2; + } + } - auto w = state(step); - std::cout << "run\n"; w->resume(); - std::cout << "run\n"; w->resume(); - std::cout << "run\n"; w->resume(); - std::cout << "set predicate (valid)\n"; state.store_reg(step.predicate->first, step.predicate->second); - std::cout << "run\n"; w->resume(); - std::cout << "run\n"; w->resume(); - std::cout << "run\n"; w->resume(); - std::cout << "set regs (all)\n"; - for (int i = 0; i < 10; ++i) - state.store_reg(i, 1000 + i); - for (bool done = false; !done; done = w->resume()) - std::cout << "run\n"; - std::cout << "huzzah!\n"; + fmt::print("Functional model exited.\n"); return 0; } diff --git a/tools/iwyu.imp b/tools/iwyu.imp new file mode 100644 index 0000000..b48e049 --- /dev/null +++ b/tools/iwyu.imp @@ -0,0 +1,3 @@ +[ + { include: [ "", private, "", public ] }, +] -- cgit v1.2.3