1 //
2 // Copyright (c) 2010-2025 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 #ifndef WishboneInitiator_H
9 #define WishboneInitiator_H
10 
11 #include "src/renode.h"
12 #include "wishbone.h"
13 
14 template <typename data_t, typename addr_t>
15 class WishboneInitiator : public WishboneBase, public BaseInitiatorBus
16 {
17 public:
WishboneInitiator()18     WishboneInitiator()
19         : readState(0), writeState(0)
20     {
21     }
22 
areSignalsConnected()23     bool areSignalsConnected()
24     {
25         return isSignalConnected(wb_clk, "wb_clk")
26             && isSignalConnected(wb_rst, "wb_rst")
27             && isSignalConnected(wb_addr, "wb_addr")
28             && isSignalConnected(wb_rd_dat, "wb_rd_dat")
29             && isSignalConnected(wb_wr_dat, "wb_wr_dat")
30             && isSignalConnected(wb_we, "wb_we")
31             && isSignalConnected(wb_sel, "wb_sel")
32             && isSignalConnected(wb_stb, "wb_stb")
33             && isSignalConnected(wb_ack, "wb_ack")
34             && isSignalConnected(wb_cyc, "wb_cyc")
35             && isSignalConnected(wb_stall, "wb_stall");
36     }
37 
tick(bool countEnable,uint64_t steps)38     void tick(bool countEnable, uint64_t steps) override
39     {
40         for (size_t i = 0; i < steps; i++)
41         {
42             readHandler();
43             writeHandler();
44             *wb_clk = high;
45             evaluateModel();
46             *wb_clk = low;
47             evaluateModel();
48         }
49 
50         clearSignals();
51 
52         if (countEnable)
53             tickCounter += steps;
54     }
55 
timeoutTick(uint8_t * signal,uint8_t expectedValue,int timeout)56     void timeoutTick(uint8_t* signal, uint8_t expectedValue, int timeout)
57     {
58         throw "Unsupported operation";
59     }
60 
readWord(uint64_t addr,uint8_t sel)61     void readWord(uint64_t addr, uint8_t sel)
62     {
63 #ifdef DEBUG
64         agent->log(LOG_LEVEL_NOISY, "Wishbone read from: 0x%" PRIX64 ", sel: %i", addr, int(sel));
65 #endif
66         data = agent->requestDoubleWordFromAgent(addr);
67 
68         constexpr size_t bits = 8;
69         for (size_t i = 0; i < bits; i++)
70         {
71             if ((sel & (1 << i)) == 0)
72                 ((uint8_t *)&data)[i] = 0;
73         }
74     }
75 
writeWord(uint64_t addr,uint64_t data,uint8_t sel)76     void writeWord(uint64_t addr, uint64_t data, uint8_t sel)
77     {
78 #ifdef DEBUG
79         agent->log(LOG_LEVEL_NOISY, "Wishbone write to: 0x%" PRIX64 ", data: 0x%" PRIX64 ", sel: %i", addr, data, int(sel));
80 #endif
81 
82         switch (sel)
83         {
84         case 1 << 0:
85             agent->pushByteToAgent(addr, ((uint8_t *)&data)[0]);
86             break;
87         case 1 << 1:
88             agent->pushByteToAgent(addr + 1, ((uint8_t *)&data)[1]);
89             break;
90         case 1 << 2:
91             agent->pushByteToAgent(addr + 2, ((uint8_t *)&data)[2]);
92             break;
93         case 1 << 3:
94             agent->pushByteToAgent(addr + 3, ((uint8_t *)&data)[3]);
95             break;
96 
97         case (1 << 0) | (1 << 1):
98             agent->pushWordToAgent(addr, data & 0xFFFF);
99             break;
100         case (1 << 2) | (1 << 3):
101             agent->pushWordToAgent(addr + 2, (data >> 16) & 0xFFFF);
102             break;
103 
104         case 15:
105             agent->pushDoubleWordToAgent(addr, data);
106             break;
107 
108         default:
109         {
110             uint64_t oldData = agent->requestDoubleWordFromAgent(addr);
111 
112             constexpr size_t bits = 8;
113             for (size_t i = 0; i < bits; i++)
114             {
115                 if (sel & (1 << i))
116                     ((uint8_t *)&oldData)[i] = ((uint8_t *)&data)[i];
117             }
118 
119             agent->pushDoubleWordToAgent(addr, oldData);
120             break;
121         }
122         }
123     }
124 
readHandler()125     void readHandler()
126     {
127         switch (readState)
128         {
129         case 0:
130             if (*wb_cyc && *wb_stb && !*wb_we)
131             {
132                 *wb_stall = low;
133                 *wb_ack = low;
134                 readWord(*wb_addr * sizeof(data_t), *wb_sel);
135                 readState = 1;
136             }
137             break;
138         case 1:
139             *wb_stall = high;
140             *wb_ack = high;
141             *wb_rd_dat = data;
142             readState = 0;
143             break;
144         }
145     }
146 
writeHandler()147     void writeHandler()
148     {
149         switch (writeState)
150         {
151         case 0:
152             if (*wb_cyc && *wb_stb && *wb_we)
153             {
154                 *wb_stall = low;
155                 *wb_ack = low;
156                 writeWord(*wb_addr * sizeof(data_t), *wb_wr_dat, *wb_sel);
157                 writeState = 1;
158             }
159             break;
160         case 1:
161             *wb_stall = high;
162             *wb_ack = high;
163             writeState = 0;
164             break;
165         }
166     }
167 
clearSignals()168     void clearSignals()
169     {
170         *wb_stall = high;
171         *wb_ack = low;
172     }
173 
reset()174     void reset()
175     {
176         *wb_rst = 1;
177         tick(true, 1);
178         *wb_rst = 0;
179         tick(true, 1);
180     }
181 
hasSpecifiedAdress()182     bool hasSpecifiedAdress() override
183     {
184         return *wb_cyc && *wb_stb;
185     }
186 
getSpecifiedAdress()187     uint64_t getSpecifiedAdress() override { return *wb_addr * sizeof(data_t); }
188 
189     addr_t *wb_addr;
190     data_t *wb_rd_dat;
191     data_t *wb_wr_dat;
192 
193     uint8_t readState, writeState;
194     uint64_t data;
195 
196     static constexpr uint32_t high = 1, low = 0;
197 };
198 
199 #endif
200