summaryrefslogtreecommitdiff
path: root/tb/avalon.hpp
blob: 347c8bdfc6dec008e53307c4deeb38c09b125405 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#ifndef TALLER_AVALON_HPP
#define TALLER_AVALON_HPP

#include <cassert>
#include <cstdint>
#include <cstdio>
#include <vector>

namespace taller::avalon
{
	class slave
	{
		public:
			inline slave(std::uint32_t base, std::uint32_t size, std::size_t word_size)
			: base(base),
			  mask(~(size - 1)),
			  word(log2i(word_size))
			{
				assert(!((word_size - 1) & word_size));
				assert(!(base & word_mask()) && !(size & word_mask()) && !((size - 1) & size));
			}

			inline std::uint32_t base_address() noexcept
			{
				return base;
			}

			inline std::uint32_t address_mask() noexcept
			{
				return mask;
			}

			inline std::uint32_t word_mask() noexcept
			{
				return (1 << word) - 1;
			}

			inline std::size_t word_size() noexcept
			{
				return 1 << word;
			}

			inline unsigned word_bits() noexcept
			{
				return word;
			}

			inline std::uint32_t address_span() noexcept
			{
				return ~mask + 1;
			}

			inline virtual void tick() noexcept
			{}

			inline virtual void bail() noexcept
			{}

			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;

		private:
			std::uint32_t base;
			std::uint32_t mask;
			unsigned      word;

			static inline int log2i(int i)
			{
		    	return sizeof(int) * 8 - __builtin_clz(i) - 1;
			}
	};

	template<class Platform>
	class interconnect
	{
		public:
			interconnect(Platform &plat) noexcept;

			bool tick(bool clk);
			void attach(slave &dev);
			void bail() noexcept;

			bool dump(std::uint32_t addr, std::uint32_t &word);
			bool patch(std::uint32_t addr, std::uint32_t readdata);

		private:
			struct binding
			{
				std::uint32_t base;
				std::uint32_t mask;
				slave         &dev;
			};

			Platform            &plat;
			slave*               active = nullptr;
			std::vector<binding> devices;
			std::uint32_t        avl_address    = 0;
			std::uint32_t        avl_writedata  = 0;
			unsigned             avl_byteenable = 0;
			bool                 avl_read       = false;
			bool                 avl_write      = false;

			slave *resolve_external(std::uint32_t avl_address);
	};
}

#include "avalon.impl.hpp"

#endif