summaryrefslogtreecommitdiff
path: root/tb
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tb/avalon.hpp46
-rw-r--r--tb/avalon.impl.hpp62
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