diff --git a/docs/source/code_examples/functional/dummy.cc b/docs/source/code_examples/functional/dummy.cc new file mode 100644 index 000000000..3d84b84ba --- /dev/null +++ b/docs/source/code_examples/functional/dummy.cc @@ -0,0 +1,44 @@ +#include "kernel/functional.h" +#include "kernel/yosys.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct FunctionalDummyBackend : public Backend { + FunctionalDummyBackend() : Backend("functional_dummy", "dump generated Functional IR") {} + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override + { + // backend pass boiler plate + log_header(design, "Executing dummy functional backend.\n"); + + size_t argidx = 1; + extra_args(f, filename, args, argidx, design); + + for (auto module : design->selected_modules()) + { + log("Processing module `%s`.\n", module->name.c_str()); + + // convert module to FunctionalIR + auto ir = Functional::IR::from_module(module); + *f << "module " << module->name.c_str() << "\n"; + + // write node functions + for (auto node : ir) + *f << " assign " << id2cstr(node.name()) + << " = " << node.to_string() << "\n"; + *f << "\n"; + + // write outputs and next state + for (auto output : ir.outputs()) + *f << " " << id2cstr(output->kind) + << " " << id2cstr(output->name) + << " = " << id2cstr(output->value().name()) << "\n"; + for (auto state : ir.states()) + *f << " " << id2cstr(state->kind) + << " " << id2cstr(state->name) + << " = " << id2cstr(state->next_value().name()) << "\n"; + } + } +} FunctionalDummyBackend; + +PRIVATE_NAMESPACE_END diff --git a/docs/source/yosys_internals/extending_yosys/functional_ir.rst b/docs/source/yosys_internals/extending_yosys/functional_ir.rst index c82a2828a..80eeeebf2 100644 --- a/docs/source/yosys_internals/extending_yosys/functional_ir.rst +++ b/docs/source/yosys_internals/extending_yosys/functional_ir.rst @@ -144,6 +144,41 @@ S-expressions can be constructed with ``SExpr::list``, for example ``SExpr expr parentheses. - The destructor calls ``flush`` but also closes all unclosed parentheses. +Example: A minimal functional backend +------------------------------------- + +.. literalinclude:: /code_examples/functional/dummy.cc + :language: c++ + :caption: Example source code for a minimal functional backend + +- three main steps needed + + + convert to FunctionalIR + + handle nodes + + handle outputs and next state + +- backend pass boiler plate gives us ``write_functional_dummy`` command +- pointer ``f`` is a ``std::ostream`` we can write to, being either a file or + stdout +- FunctionalIR conversion done by ``Functional::IR::from_module()`` +- each node performs some function or operation (including reading input/current + state) + + + each variable is assigned exactly once before being used + + ``node.name()`` returns a ``RTLIL::IdString``, which we convert for + printing with ``id2cstr()`` + + ``node.to_string()`` converts the node into a string of the form + ``function(args)`` + + * ``function`` is the result of ``Functional::IR::fn_to_string(node.fn())`` + * ``args`` are the zero or more arguments passed to the function, most + commonly the name of another node + * wraps ``node.visit()`` with a private visitor with return type + ``std::string`` + +- ``Functional::IROutput::value()`` and ``Functional::IRState::next_value()`` + represent the outputs of our function + Example: Adapting SMT-LIB backend for Rosette ---------------------------------------------