diff options
| author | Alejandro Soto <alejandro@34project.org> | 2022-09-18 00:39:21 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2022-09-18 00:39:21 -0600 |
| commit | d743c48b821bad11943b77bdc9a5d9d975fd8cb0 (patch) | |
| tree | 2097ce1618b876cc85172ea85c3165462e052c5e /tb | |
| parent | b0cb20496d88cd017c4c51243d16ac3b060cc1d6 (diff) | |
Add Avalon-MM emulator
Diffstat (limited to '')
| -rw-r--r-- | tb/avalon.hpp | 46 | ||||
| -rw-r--r-- | tb/avalon.impl.hpp | 62 |
2 files changed, 108 insertions, 0 deletions
diff --git a/tb/avalon.hpp b/tb/avalon.hpp new file mode 100644 index 0000000..38c8792 --- /dev/null +++ b/tb/avalon.hpp @@ -0,0 +1,46 @@ +#ifndef AVALON_HPP +#define AVALON_HPP + +#include <cstdint> +#include <vector> + +namespace taller::avalon +{ + class slave + { + public: + virtual std::uint32_t base_address() = 0; + virtual std::uint32_t address_mask() = 0; + + virtual bool read(std::uint32_t addr, std::uint32_t &data) = 0; + virtual bool write(std::uint32_t addr, std::uint32_t data, unsigned byte_enable) = 0; + }; + + template<class Platform> + class interconnect + { + public: + inline interconnect(Platform &plat) noexcept + : plat(plat) + {} + + void tick(); + void attach(slave &dev); + + private: + struct binding + { + std::uint32_t base; + std::uint32_t mask; + slave &dev; + }; + + Platform &plat; + slave* active = nullptr; + std::vector<binding> devices; + }; +} + +#include "avalon.impl.hpp" + +#endif diff --git a/tb/avalon.impl.hpp b/tb/avalon.impl.hpp new file mode 100644 index 0000000..7f589ae --- /dev/null +++ b/tb/avalon.impl.hpp @@ -0,0 +1,62 @@ +#ifndef AVALON_IMPL_HPP +#define AVALON_IMPL_HPP + +#include <cassert> +#include <cstdio> + +namespace taller::avalon +{ + template<class Platform> + void interconnect<Platform>::attach(slave &dev) + { + devices.push_back(binding { dev.base_address(), dev.address_mask(), dev }); + } + + template<class Platform> + void interconnect<Platform>::tick() + { + auto addr = plat.avl_address; + if(!active) + { + if(addr & 0b11) + { + fprintf(stderr, "[avl] unaligned address: 0x%08x\n", addr); + assert(false); + } + + for(auto &binding : devices) + { + if((addr & binding.mask) == binding.base) + { + active = &binding.dev; + break; + } + } + + if(!active) + { + const char *op = plat.avl_read ? "read" : "write"; + fprintf(stderr, "[avl] attempt to %s memory hole at 0x%08x\n", op, addr); + assert(false); + } + } + + assert(!plat.avl_read || !plat.avl_write); + auto pos = addr >> 2; + + if(plat.avl_read) + { + plat.avl_waitrequest = !active->read(pos, plat.avl_readdata); + } else if(plat.avl_write) + { + plat.avl_waitrequest = !active->write(pos, plat.avl_writedata, plat.avl_byteenable); + } + + if(!plat.avl_waitrequest) + { + active = nullptr; + } + } +} + +#endif |
