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 #include "renode_bus.h"
8 #include "communication/socket_channel.h"
9 #include "src/renode.h"
10 static RenodeAgent* renodeAgent;
11 
12 #define IO_THREADS 1
13 
14 //=================================================
15 // RenodeAgent
16 //=================================================
17 
RenodeAgent()18 RenodeAgent::RenodeAgent() { }
19 
addBus(BaseBus * bus)20 void RenodeAgent::addBus(BaseBus* bus)
21 {
22     bus->setAgent(this);
23     if(targetInterfaces.empty())
24     {
25         firstInterface = bus;
26     }
27 }
addBus(BaseTargetBus * bus)28 void RenodeAgent::addBus(BaseTargetBus* bus)
29 {
30     addBus((BaseBus*)bus);
31     targetInterfaces.push_back(std::unique_ptr<BaseTargetBus>(bus));
32 }
33 
addBus(BaseInitiatorBus * bus)34 void RenodeAgent::addBus(BaseInitiatorBus* bus)
35 {
36     addBus((BaseBus*)bus);
37     initatorInterfaces.push_back(std::unique_ptr<BaseInitiatorBus>(bus));
38 }
39 
writeToBus(int width,uint64_t addr,uint64_t value)40 void RenodeAgent::writeToBus(int width, uint64_t addr, uint64_t value)
41 {
42     try {
43         targetInterfaces[0]->write(width, addr, value);
44         communicationChannel->sendMain(Protocol(ok, 0, 0));
45     }
46     catch(const char* msg) {
47         log(LOG_LEVEL_ERROR, msg);
48         communicationChannel->sendMain(Protocol(error, 0, 0));
49     }
50 }
51 
readFromBus(int width,uint64_t addr)52 void RenodeAgent::readFromBus(int width, uint64_t addr)
53 {
54     try {
55         uint64_t readValue = targetInterfaces[0]->read(width, addr);
56         communicationChannel->sendMain(Protocol(readRequest, addr, readValue));
57     }
58     catch(const char* msg) {
59         log(LOG_LEVEL_ERROR, msg);
60         communicationChannel->sendMain(Protocol(error, 0, 0));
61     }
62 }
63 
pushByteToAgent(uint64_t addr,uint8_t value)64 void RenodeAgent::pushByteToAgent(uint64_t addr, uint8_t value)
65 {
66     pushToAgent(pushByte, addr, value);
67 }
68 
pushWordToAgent(uint64_t addr,uint16_t value)69 void RenodeAgent::pushWordToAgent(uint64_t addr, uint16_t value)
70 {
71     pushToAgent(pushWord, addr, value);
72 }
73 
pushDoubleWordToAgent(uint64_t addr,uint32_t value)74 void RenodeAgent::pushDoubleWordToAgent(uint64_t addr, uint32_t value)
75 {
76     pushToAgent(pushDoubleWord, addr, value);
77 }
78 
requestDoubleWordFromAgent(uint64_t addr)79 uint64_t RenodeAgent::requestDoubleWordFromAgent(uint64_t addr)
80 {
81     return requestFromAgent(getDoubleWord, addr);
82 }
83 
pushToAgent(Action action,uint64_t addr,uint64_t value)84 void RenodeAgent::pushToAgent(Action action, uint64_t addr, uint64_t value)
85 {
86     communicationChannel->sendSender(Protocol(action, addr, value));
87     Protocol* received = communicationChannel->receive();
88     while (received->actionId != pushConfirmation)
89     {
90         handleRequest(received);
91         delete received;
92         received = communicationChannel->receive();
93     }
94     delete received;
95 }
96 
requestFromAgent(Action action,uint64_t addr)97 uint64_t RenodeAgent::requestFromAgent(Action action, uint64_t addr)
98 {
99     communicationChannel->sendSender(Protocol(action, addr, 0));
100     Protocol* received = communicationChannel->receive();
101     while (received->actionId != writeRequest)
102     {
103         handleRequest(received);
104         delete received;
105         received = communicationChannel->receive();
106     }
107     auto result = received->value;
108     delete received;
109     return result;
110 }
111 
tick(bool countEnable,uint64_t steps)112 void RenodeAgent::tick(bool countEnable, uint64_t steps)
113 {
114     for(auto& b : targetInterfaces)
115         b->tick(countEnable, steps);
116     for(auto& b : initatorInterfaces)
117         b->tick(countEnable, steps);
118 }
119 
timeoutTick(uint8_t * signal,uint8_t expectedValue,int timeout)120 void RenodeAgent::timeoutTick(uint8_t* signal, uint8_t expectedValue, int timeout)
121 {
122     for(auto& b : targetInterfaces)
123         b->timeoutTick(signal, expectedValue, timeout);
124     for(auto& b : initatorInterfaces)
125         b->timeoutTick(signal, expectedValue, timeout);
126 }
127 
reset()128 void RenodeAgent::reset()
129 {
130     for(auto& b : targetInterfaces)
131         b->reset();
132     for(auto& b : initatorInterfaces)
133         b->reset();
134 }
135 
fatalError()136 void RenodeAgent::fatalError()
137 {
138     communicationChannel->sendSender(Protocol(error, 0, 0));
139     handleDisconnect();
140 }
141 
handleCustomRequestType(Protocol * message)142 void RenodeAgent::handleCustomRequestType(Protocol* message)
143 {
144     log(LOG_LEVEL_WARNING, "Unhandled request type: %d", message->actionId);
145 }
146 
log(int level,const char * fmt,...)147 void RenodeAgent::log(int level, const char* fmt, ...)
148 {
149     char s[1024];
150     va_list ap;
151     va_start(ap, fmt);
152     vsnprintf(s, 1024, fmt, ap);
153     communicationChannel->log(level, s);
154     va_end(ap);
155 }
156 
receive()157 Protocol* RenodeAgent::receive()
158 {
159     return communicationChannel->receive();
160 }
161 
registerInterrupt(uint8_t * irq,uint8_t irq_addr)162 void RenodeAgent::registerInterrupt(uint8_t *irq, uint8_t irq_addr)
163 {
164     if (irq == nullptr) {
165         log(LOG_LEVEL_ERROR, "The irq address cannot be null");
166         communicationChannel->sendMain(Protocol(error, 0, 0));
167         return;
168     }
169 
170     interrupts.push_back({irq, 0, irq_addr});
171 }
172 
handleInterrupts(void)173 void RenodeAgent::handleInterrupts(void)
174 {
175     for (unsigned long i = 0; i < interrupts.size(); i++) {
176         if (*interrupts[i].irq != interrupts[i].prev_irq) {
177             communicationChannel->sendSender(Protocol(interrupt, interrupts[i].irq_addr, *interrupts[i].irq));
178             interrupts[i].prev_irq = *interrupts[i].irq;
179         }
180     }
181 }
182 
connect(int receiverPort,int senderPort,const char * address)183 void RenodeAgent::connect(int receiverPort, int senderPort, const char* address)
184 {
185     renodeAgent = this;
186     SocketCommunicationChannel* channel = new SocketCommunicationChannel();
187     communicationChannel = channel;
188     channel->connect(receiverPort, senderPort, address);
189 }
190 
connectNative()191 void RenodeAgent::connectNative()
192 {
193     renodeAgent = this;
194     communicationChannel = new NativeCommunicationChannel;
195 }
196 
simulate()197 void RenodeAgent::simulate()
198 {
199     Protocol* result;
200     reset();
201 
202     while(communicationChannel->isConnected()) {
203         result = receive();
204         handleRequest(result);
205         delete result;
206     }
207 }
208 
handleRequest(Protocol * request)209 void RenodeAgent::handleRequest(Protocol* request)
210 {
211     switch(request->actionId) {
212         case invalidAction:
213             break;
214         case tickClock:
215         {
216             long ticks = request->value - firstInterface->tickCounter;
217             if(ticks < 0) {
218                 firstInterface->tickCounter -= request->value;
219             }
220             else {
221                 tick(false, ticks);
222             }
223             firstInterface->tickCounter = 0;
224             communicationChannel->sendSender(Protocol(tickClock, 0, 0));
225         }
226             break;
227         case writeRequestByte:
228             writeToBus(1, request->addr, request->value);
229             break;
230         case writeRequestWord:
231             writeToBus(2, request->addr, request->value);
232             break;
233         case writeRequest: // due to historical reasons, writeRequest defaults to 32bits
234         case writeRequestDoubleWord:
235             writeToBus(4, request->addr, request->value);
236             break;
237         case writeRequestQuadWord:
238             writeToBus(8, request->addr, request->value);
239             break;
240         case readRequestByte:
241             readFromBus(1, request->addr);
242             break;
243         case readRequestWord:
244             readFromBus(2, request->addr);
245             break;
246         case readRequest: // due to historical reasons, writeRequest defaults to 32bits
247         case readRequestDoubleWord:
248             readFromBus(4, request->addr);
249             break;
250         case readRequestQuadWord:
251             readFromBus(8, request->addr);
252             break;
253         case resetPeripheral:
254             reset();
255             break;
256         case disconnect:
257             handleDisconnect();
258             break;
259         default:
260             handleCustomRequestType(request);
261             break;
262     }
263 }
264 
handleDisconnect()265 void RenodeAgent::handleDisconnect()
266 {
267     SocketCommunicationChannel* channel;
268     if((channel = dynamic_cast<SocketCommunicationChannel*>(communicationChannel)) != nullptr) {
269         communicationChannel->sendSender(Protocol(ok, 0, 0));
270         channel->disconnect();
271     }
272 }
273 
274 //=================================================
275 // NativeCommunicationChannel
276 //=================================================
277 
278 extern void handleMainMessage(void* ptr);
279 extern void handleSenderMessage(void* ptr);
280 extern void receive(void* ptr);
281 
282 EXTERNAL_AS(void, HandleMainMessage, handleMainMessage, voidptr);
283 EXTERNAL_AS(void, HandleSenderMessage, handleSenderMessage, voidptr);
284 EXTERNAL_AS(void, Receive, receive, voidptr);
285 
sendMain(const Protocol message)286 void NativeCommunicationChannel::sendMain(const Protocol message)
287 {
288     handleMainMessage(new Protocol(message));
289 }
290 
sendSender(const Protocol message)291 void NativeCommunicationChannel::sendSender(const Protocol message)
292 {
293     handleSenderMessage(new Protocol(message));
294 }
295 
log(int logLevel,const char * data)296 void NativeCommunicationChannel::log(int logLevel, const char* data)
297 {
298     handleSenderMessage(new Protocol(logMessage, strlen(data) + 1, (uint64_t)data));
299     handleSenderMessage(new Protocol(logMessage, 0, logLevel));
300 }
301 
isConnected()302 bool NativeCommunicationChannel::isConnected()
303 {
304     return true;
305 }
306 
receive()307 Protocol* NativeCommunicationChannel::receive()
308 {
309     Protocol* message = new Protocol;
310     ::receive(message);
311     return message;
312 }
313 
314 //=================================================
315 // Functions exported to Renode
316 //=================================================
317 
initialize_native()318 void initialize_native()
319 {
320     renodeAgent = Init();
321 }
322 
handle_request(Protocol * request)323 void handle_request(Protocol* request)
324 {
325     renodeAgent->handleRequest(request);
326 }
327 
reset_peripheral()328 void reset_peripheral()
329 {
330     renodeAgent->reset();
331 }
332