build/sim: improve timebase calculation (strict checks) and update modules
[litex.git] / litex / build / sim / core / modules / xgmii_ethernet / xgmii_ethernet.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "error.h"
6
7 #include <event2/listener.h>
8 #include <event2/util.h>
9 #include <event2/event.h>
10 #include <json-c/json.h>
11 #include "tapcfg.h"
12 #include "modules.h"
13
14 #define ETH_LEN 9000
15 struct eth_packet_s {
16 char data[ETH_LEN];
17 size_t len;
18 struct eth_packet_s *next;
19 };
20
21 #define DW_64
22 struct session_s {
23 #ifdef DW_64
24 unsigned long int tx;
25 unsigned long int rx;
26 #else
27 unsigned int tx;
28 unsigned int rx;
29 #endif
30 char tx_valid;
31 char rx_valid;
32 char rx_ready;
33
34 #ifdef DW_64
35 unsigned long int *tx_data;
36 unsigned long int *rx_data;
37 #else
38 unsigned int *tx_data;
39 unsigned int *rx_data;
40 #endif
41
42 char *tx_ctl;
43 char terminate;
44 char preamble;
45 char *rx_ctl;
46 char *sys_clk;
47
48 tapcfg_t *tapcfg;
49 int fd;
50 char databuf[ETH_LEN];
51 char rx_state;
52 int datalen;
53 char inbuf[ETH_LEN];
54 int inlen;
55 int insent;
56 struct eth_packet_s *ethpack;
57 struct event *ev;
58 };
59
60 static struct event_base *base=NULL;
61
62 int litex_sim_module_get_args(char *args, char *arg, char **val)
63 {
64 int ret = RC_OK;
65 json_object *jsobj = NULL;
66 json_object *obj = NULL;
67 char *value = NULL;
68 int r;
69
70 jsobj = json_tokener_parse(args);
71 if(NULL == jsobj) {
72 fprintf(stderr, "Error parsing json arg: %s \n", args);
73 ret = RC_JSERROR;
74 goto out;
75 }
76
77 if(!json_object_is_type(jsobj, json_type_object)) {
78 fprintf(stderr, "Arg must be type object! : %s \n", args);
79 ret = RC_JSERROR;
80 goto out;
81 }
82
83 obj=NULL;
84 r = json_object_object_get_ex(jsobj, arg, &obj);
85 if(!r) {
86 fprintf(stderr, "Could not find object: \"%s\" (%s)\n", arg, args);
87 ret = RC_JSERROR;
88 goto out;
89 }
90 value = strdup(json_object_get_string(obj));
91
92 out:
93 *val = value;
94 return ret;
95 }
96
97 static int litex_sim_module_pads_get(struct pad_s *pads, char *name, void **signal)
98 {
99 int ret = RC_OK;
100 void *sig = NULL;
101 int i;
102
103 if(!pads || !name || !signal) {
104 ret=RC_INVARG;
105 goto out;
106 }
107
108 i = 0;
109 while(pads[i].name) {
110 if(!strcmp(pads[i].name, name)) {
111 sig=(void*)pads[i].signal;
112 break;
113 }
114 i++;
115 }
116
117 out:
118 *signal=sig;
119 return ret;
120 }
121
122 static int xgmii_ethernet_start(void *b)
123 {
124 base = (struct event_base *) b;
125 printf("[xgmii_ethernet] loaded (%p)\n", base);
126 return RC_OK;
127 }
128
129 void event_handler(int fd, short event, void *arg)
130 {
131 struct session_s *s = (struct session_s*)arg;
132 struct eth_packet_s *ep;
133 struct eth_packet_s *tep;
134
135 if (event & EV_READ) {
136 ep = malloc(sizeof(struct eth_packet_s));
137 memset(ep, 0, sizeof(struct eth_packet_s));
138 ep->len = tapcfg_read(s->tapcfg, ep->data, ETH_LEN);
139 if(ep->len < 60)
140 ep->len = 60;
141
142 if(!s->ethpack)
143 s->ethpack = ep;
144 else {
145 for(tep=s->ethpack; tep->next; tep=tep->next);
146 tep->next = ep;
147 }
148 }
149 }
150
151 static const char macadr[6] = {0xaa, 0xb6, 0x24, 0x69, 0x77, 0x21};
152
153 static int xgmii_ethernet_new(void **sess, char *args)
154 {
155 int ret = RC_OK;
156 char *c_tap = NULL;
157 char *c_tap_ip = NULL;
158 struct session_s *s = NULL;
159 struct timeval tv = {10, 0};
160 if(!sess) {
161 ret = RC_INVARG;
162 goto out;
163 }
164
165 s=(struct session_s*)malloc(sizeof(struct session_s));
166 if(!s) {
167 ret=RC_NOENMEM;
168 goto out;
169 }
170 memset(s, 0, sizeof(struct session_s));
171
172 ret = litex_sim_module_get_args(args, "interface", &c_tap);
173 {
174 if(RC_OK != ret)
175 goto out;
176 }
177 ret = litex_sim_module_get_args(args, "ip", &c_tap_ip);
178 {
179 if(RC_OK != ret)
180 goto out;
181 }
182
183 s->tapcfg = tapcfg_init();
184 tapcfg_start(s->tapcfg, c_tap, 0);
185 s->fd = tapcfg_get_fd(s->tapcfg);
186 tapcfg_iface_set_hwaddr(s->tapcfg, macadr, 6);
187 tapcfg_iface_set_ipv4(s->tapcfg, c_tap_ip, 24);
188 tapcfg_iface_set_status(s->tapcfg, TAPCFG_STATUS_ALL_UP);
189 free(c_tap);
190 free(c_tap_ip);
191
192 s->ev = event_new(base, s->fd, EV_READ | EV_PERSIST, event_handler, s);
193 event_add(s->ev, &tv);
194
195 out:
196 *sess=(void*)s;
197 return ret;
198 }
199
200 static int xgmii_ethernet_add_pads(void *sess, struct pad_list_s *plist)
201 {
202 int ret = RC_OK;
203 struct session_s *s = (struct session_s*)sess;
204 struct pad_s *pads;
205 if(!sess || !plist) {
206 ret = RC_INVARG;
207 goto out;
208 }
209 pads = plist->pads;
210 if(!strcmp(plist->name, "eth")) {
211 litex_sim_module_pads_get(pads, "rx_data", (void**)&s->rx_data);
212 litex_sim_module_pads_get(pads, "rx_ctl", (void**)&s->rx_ctl);
213 litex_sim_module_pads_get(pads, "tx_data", (void**)&s->tx_data);
214 litex_sim_module_pads_get(pads, "tx_ctl", (void**)&s->tx_ctl);
215 }
216
217 if(!strcmp(plist->name, "sys_clk"))
218 litex_sim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
219
220 out:
221 return ret;
222 }
223
224 #ifdef DW_64
225 char g_preamble = 0;
226 char g_dw = 64;
227 unsigned long int g_mask = 0xff;
228 unsigned long int g_idle = 0x0707070707070707;
229 #else
230 char g_preamble = 0;
231 char g_dw = 32;
232 unsigned int g_mask = 0xff;
233 unsigned int g_idle = 0x07070707;
234 #endif
235
236 static int xgmii_ethernet_tick(void *sess, uint64_t time_ps)
237 {
238 static struct clk_edge_t edge;
239 struct session_s *s = (struct session_s*)sess;
240 struct eth_packet_s *pep;
241
242 if(!clk_pos_edge(&edge, *s->sys_clk)) {
243 s->preamble=0;
244 return RC_OK;
245 }
246
247 #ifdef DW_64
248 unsigned long int u;
249 #else
250 unsigned int u;
251 #endif
252 // XGMII stuff
253 u = *s->tx_data;
254 s->tx = u;
255 // printf("%16lx\t\t%x\n", u, *s->tx_ctl & g_mask);
256 if (u != g_idle) {
257 // printf("%16lx\t\t%x\n", u, *s->tx_ctl & g_mask);
258 // printf("preamble: %02x\n", g_preamble);
259 }
260
261 if ((g_preamble == 0) && (*s->tx_ctl & g_mask) == 0x1) {
262 g_preamble = (g_dw == 64)? 2: 1;
263 } else if (g_preamble == 1) {
264 g_preamble = 2;
265 } else if (g_preamble == 2) {
266 if ((*s->tx_ctl & g_mask) != 0) {
267 // Intentionally ignoring errors for now (since we don't really have retransmission)
268 // So this means last word
269 // TODO: Check for end of frame mid word
270 for (int m = 0; m < (g_dw >> 3); m++) {
271 char mask = 1 << m;
272 if ((*s->tx_ctl & mask) == 0)
273 s->databuf[s->datalen++] = (char) ((u & (g_mask << (8*m))) >> (8*m));
274 }
275
276 // Enable for debugging
277 printf("Sending: \n");
278 for(int i=0; i < s->datalen; printf("%02x ", s->databuf[i++] & 0xff));
279 printf("\n%u\n", s->datalen);
280 printf("Sent %u\n", s->datalen);
281 tapcfg_write(s->tapcfg, s->databuf, s->datalen);
282 s->datalen=0;
283 g_preamble=0;
284 } else {
285 for (int i = 0; i < (g_dw >> 3); i++) {
286 assert(s->datalen <= ETH_LEN);
287 s->databuf[s->datalen++]= (char) ((u & (g_mask << (8 * i))) >> (8*i));
288 }
289 }
290 }
291
292 #ifdef DW_64
293 unsigned long int local_data = 0x0707070707070707;
294 unsigned long int temp_data = 0; // This is here just to avoid an ugly cast later
295 #else
296 unsigned int local_data = 0x07070707;
297 unsigned int temp_data = 0;
298 #endif
299 char temp_ctl = 0;
300 char local_ctl = 0;
301 if(s->inlen) {
302 // printf("%x ", s->rx_state);
303 if (s->rx_state == 0) {
304 *s->rx_data = 0xd5555555555555fb;
305 *s->rx_ctl = 1;
306 s->rx_state = 1;
307 } else if ((s->rx_state == 1) && (s->insent + (g_dw >> 3) < s->inlen)) {
308 *s->rx_ctl = 0;
309 local_data = 0;
310 for (unsigned int i = 0; i < (g_dw >> 3); i++) {
311 temp_data = (unsigned char) s->inbuf[s->insent++];
312 local_data |= (temp_data << (i << 3));
313 }
314 *s->rx_data = local_data;
315 } else if ((s->rx_state == 1) && (s->insent + (g_dw >> 3) >= s->inlen)) {
316 // printf("%d, %d\n", s->insent, s->inlen);
317 local_data = 0;
318 for (unsigned int i = 0; i < (g_dw >> 3); i++) {
319 if (s->insent < s->inlen) {
320 temp_data = (unsigned char) s->inbuf[s->insent++];
321 } else if (s->insent == s->inlen) {
322 temp_data = (unsigned char) 0xfd;
323 temp_ctl = 1;
324 s->insent++;
325 } else {
326 temp_data = (unsigned char) 0x07;
327 temp_ctl = 1;
328 s->insent++;
329 }
330 local_data |= (temp_data << (i << 3));
331 local_ctl |= (temp_ctl << i);
332 //printf("%16lx %02x\n", local_data, local_ctl);
333 }
334 *s->rx_data = local_data;
335 *s->rx_ctl = local_ctl;
336 if (s->insent == s->inlen)
337 s->rx_state = 2;
338 else {
339 s->insent = 0;
340 s->inlen = 0;
341 s->rx_state = 0;
342 }
343 } else if (s->rx_state == 2) {
344 *s->rx_ctl = 0xff;
345 *s->rx_data = 0x07070707070707fd;
346 s->insent =0;
347 s->inlen = 0;
348 s->rx_state = 0;
349 } else {
350 *s->rx_ctl = 0xff;
351 *s->rx_data = local_data;
352 }
353 // printf("%x, %16lx, %x\n", s->rx_state, *s->rx_data, *s->rx_ctl);
354 } else {
355 *s->rx_ctl = 0xff;
356 *s->rx_data = local_data;
357 if(s->ethpack) {
358 memcpy(s->inbuf, s->ethpack->data, s->ethpack->len);
359 printf("Received: %ld\n", s->ethpack->len );
360 for(int i=0; i< s->ethpack->len;) {
361 printf("%02x ", s->inbuf[i++] & 0xff);
362 }
363 printf("\n");
364 s->inlen = s->ethpack->len;
365 pep=s->ethpack->next;
366 free(s->ethpack);
367 s->ethpack=pep;
368 }
369 }
370 return RC_OK;
371 }
372
373 static struct ext_module_s ext_mod = {
374 "xgmii_ethernet",
375 xgmii_ethernet_start,
376 xgmii_ethernet_new,
377 xgmii_ethernet_add_pads,
378 NULL,
379 xgmii_ethernet_tick
380 };
381
382 int litex_sim_ext_module_init(int (*register_module)(struct ext_module_s *))
383 {
384 int ret = RC_OK;
385 ret = register_module(&ext_mod);
386 return ret;
387 }