1
2
3
4
5
6
7
8
9
10#include "hw.h"
11#include "net.h"
12#include "devices.h"
13
14#include <zlib.h>
15
16
17#define NUM_PACKETS 4
18
19typedef struct {
20 VLANClientState *vc;
21 uint16_t tcr;
22 uint16_t rcr;
23 uint16_t cr;
24 uint16_t ctr;
25 uint16_t gpr;
26 uint16_t ptr;
27 uint16_t ercv;
28 qemu_irq irq;
29 int bank;
30 int packet_num;
31 int tx_alloc;
32
33 int allocated;
34 int tx_fifo_len;
35 int tx_fifo[NUM_PACKETS];
36 int rx_fifo_len;
37 int rx_fifo[NUM_PACKETS];
38 int tx_fifo_done_len;
39 int tx_fifo_done[NUM_PACKETS];
40
41 uint8_t data[NUM_PACKETS][2048];
42 uint8_t int_level;
43 uint8_t int_mask;
44 uint8_t macaddr[6];
45} smc91c111_state;
46
47#define RCR_SOFT_RST 0x8000
48#define RCR_STRIP_CRC 0x0200
49#define RCR_RXEN 0x0100
50
51#define TCR_EPH_LOOP 0x2000
52#define TCR_NOCRC 0x0100
53#define TCR_PAD_EN 0x0080
54#define TCR_FORCOL 0x0004
55#define TCR_LOOP 0x0002
56#define TCR_TXEN 0x0001
57
58#define INT_MD 0x80
59#define INT_ERCV 0x40
60#define INT_EPH 0x20
61#define INT_RX_OVRN 0x10
62#define INT_ALLOC 0x08
63#define INT_TX_EMPTY 0x04
64#define INT_TX 0x02
65#define INT_RCV 0x01
66
67#define CTR_AUTO_RELEASE 0x0800
68#define CTR_RELOAD 0x0002
69#define CTR_STORE 0x0001
70
71#define RS_ALGNERR 0x8000
72#define RS_BRODCAST 0x4000
73#define RS_BADCRC 0x2000
74#define RS_ODDFRAME 0x1000
75#define RS_TOOLONG 0x0800
76#define RS_TOOSHORT 0x0400
77#define RS_MULTICAST 0x0001
78
79
80static void smc91c111_update(smc91c111_state *s)
81{
82 int level;
83
84 if (s->tx_fifo_len == 0)
85 s->int_level |= INT_TX_EMPTY;
86 if (s->tx_fifo_done_len != 0)
87 s->int_level |= INT_TX;
88 level = (s->int_level & s->int_mask) != 0;
89 qemu_set_irq(s->irq, level);
90}
91
92
93static int smc91c111_allocate_packet(smc91c111_state *s)
94{
95 int i;
96 if (s->allocated == (1 << NUM_PACKETS) - 1) {
97 return 0x80;
98 }
99
100 for (i = 0; i < NUM_PACKETS; i++) {
101 if ((s->allocated & (1 << i)) == 0)
102 break;
103 }
104 s->allocated |= 1 << i;
105 return i;
106}
107
108
109
110static void smc91c111_tx_alloc(smc91c111_state *s)
111{
112 s->tx_alloc = smc91c111_allocate_packet(s);
113 if (s->tx_alloc == 0x80)
114 return;
115 s->int_level |= INT_ALLOC;
116 smc91c111_update(s);
117}
118
119
120static void smc91c111_pop_rx_fifo(smc91c111_state *s)
121{
122 int i;
123
124 s->rx_fifo_len--;
125 if (s->rx_fifo_len) {
126 for (i = 0; i < s->rx_fifo_len; i++)
127 s->rx_fifo[i] = s->rx_fifo[i + 1];
128 s->int_level |= INT_RCV;
129 } else {
130 s->int_level &= ~INT_RCV;
131 }
132 smc91c111_update(s);
133}
134
135
136static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
137{
138 int i;
139
140 if (s->tx_fifo_done_len == 0)
141 return;
142 s->tx_fifo_done_len--;
143 for (i = 0; i < s->tx_fifo_done_len; i++)
144 s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
145}
146
147
148static void smc91c111_release_packet(smc91c111_state *s, int packet)
149{
150 s->allocated &= ~(1 << packet);
151 if (s->tx_alloc == 0x80)
152 smc91c111_tx_alloc(s);
153}
154
155
156static void smc91c111_do_tx(smc91c111_state *s)
157{
158 int i;
159 int len;
160 int control;
161 int add_crc;
162 int packetnum;
163 uint8_t *p;
164
165 if ((s->tcr & TCR_TXEN) == 0)
166 return;
167 if (s->tx_fifo_len == 0)
168 return;
169 for (i = 0; i < s->tx_fifo_len; i++) {
170 packetnum = s->tx_fifo[i];
171 p = &s->data[packetnum][0];
172
173 *(p++) = 0x01;
174 *(p++) = 0x40;
175 len = *(p++);
176 len |= ((int)*(p++)) << 8;
177 len -= 6;
178 control = p[len + 1];
179 if (control & 0x20)
180 len++;
181
182
183 if (len < 64 && (s->tcr & TCR_PAD_EN)) {
184 memset(p + len, 0, 64 - len);
185 len = 64;
186 }
187#if 0
188
189
190
191
192 add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
193 if (add_crc) {
194 uint32_t crc;
195
196 crc = crc32(~0, p, len);
197 memcpy(p + len, &crc, 4);
198 len += 4;
199 }
200#else
201 add_crc = 0;
202#endif
203 if (s->ctr & CTR_AUTO_RELEASE)
204
205 smc91c111_release_packet(s, packetnum);
206 else if (s->tx_fifo_done_len < NUM_PACKETS)
207 s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
208 qemu_send_packet(s->vc, p, len);
209 }
210 s->tx_fifo_len = 0;
211 smc91c111_update(s);
212}
213
214
215static void smc91c111_queue_tx(smc91c111_state *s, int packet)
216{
217 if (s->tx_fifo_len == NUM_PACKETS)
218 return;
219 s->tx_fifo[s->tx_fifo_len++] = packet;
220 smc91c111_do_tx(s);
221}
222
223static void smc91c111_reset(smc91c111_state *s)
224{
225 s->bank = 0;
226 s->tx_fifo_len = 0;
227 s->tx_fifo_done_len = 0;
228 s->rx_fifo_len = 0;
229 s->allocated = 0;
230 s->packet_num = 0;
231 s->tx_alloc = 0;
232 s->tcr = 0;
233 s->rcr = 0;
234 s->cr = 0xa0b1;
235 s->ctr = 0x1210;
236 s->ptr = 0;
237 s->ercv = 0x1f;
238 s->int_level = INT_TX_EMPTY;
239 s->int_mask = 0;
240 smc91c111_update(s);
241}
242
243#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
244#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
245
246static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
247 uint32_t value)
248{
249 smc91c111_state *s = (smc91c111_state *)opaque;
250
251 if (offset == 14) {
252 s->bank = value;
253 return;
254 }
255 if (offset == 15)
256 return;
257 switch (s->bank) {
258 case 0:
259 switch (offset) {
260 case 0:
261 SET_LOW(tcr, value);
262 return;
263 case 1:
264 SET_HIGH(tcr, value);
265 return;
266 case 4:
267 SET_LOW(rcr, value);
268 return;
269 case 5:
270 SET_HIGH(rcr, value);
271 if (s->rcr & RCR_SOFT_RST)
272 smc91c111_reset(s);
273 return;
274 case 10: case 11:
275
276 return;
277 }
278 break;
279
280 case 1:
281 switch (offset) {
282 case 0:
283 SET_LOW(cr, value);
284 return;
285 case 1:
286 SET_HIGH(cr,value);
287 return;
288 case 2: case 3:
289 case 4: case 5: case 6: case 7: case 8: case 9:
290
291 return;
292 case 10:
293 SET_LOW(gpr, value);
294 return;
295 case 11:
296 SET_HIGH(gpr, value);
297 return;
298 case 12:
299 if (value & 1)
300 fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
301 if (value & 2)
302 fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
303 value &= ~3;
304 SET_LOW(ctr, value);
305 return;
306 case 13:
307 SET_HIGH(ctr, value);
308 return;
309 }
310 break;
311
312 case 2:
313 switch (offset) {
314 case 0:
315 switch (value >> 5) {
316 case 0:
317 break;
318 case 1:
319 s->tx_alloc = 0x80;
320 s->int_level &= ~INT_ALLOC;
321 smc91c111_update(s);
322 smc91c111_tx_alloc(s);
323 break;
324 case 2:
325 s->allocated = 0;
326 s->tx_fifo_len = 0;
327 s->tx_fifo_done_len = 0;
328 s->rx_fifo_len = 0;
329 s->tx_alloc = 0;
330 break;
331 case 3:
332 smc91c111_pop_rx_fifo(s);
333 break;
334 case 4:
335 if (s->rx_fifo_len > 0) {
336 smc91c111_release_packet(s, s->rx_fifo[0]);
337 }
338 smc91c111_pop_rx_fifo(s);
339 break;
340 case 5:
341 smc91c111_release_packet(s, s->packet_num);
342 break;
343 case 6:
344 smc91c111_queue_tx(s, s->packet_num);
345 break;
346 case 7:
347 s->tx_fifo_len = 0;
348 s->tx_fifo_done_len = 0;
349 break;
350 }
351 return;
352 case 1:
353
354 return;
355 case 2:
356 s->packet_num = value;
357 return;
358 case 3: case 4: case 5:
359
360 return;
361 case 6:
362 SET_LOW(ptr, value);
363 return;
364 case 7:
365 SET_HIGH(ptr, value);
366 return;
367 case 8: case 9: case 10: case 11:
368 {
369 int p;
370 int n;
371
372 if (s->ptr & 0x8000)
373 n = s->rx_fifo[0];
374 else
375 n = s->packet_num;
376 p = s->ptr & 0x07ff;
377 if (s->ptr & 0x4000) {
378 s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
379 } else {
380 p += (offset & 3);
381 }
382 s->data[n][p] = value;
383 }
384 return;
385 case 12:
386 s->int_level &= ~(value & 0xd6);
387 if (value & INT_TX)
388 smc91c111_pop_tx_fifo_done(s);
389 smc91c111_update(s);
390 return;
391 case 13:
392 s->int_mask = value;
393 smc91c111_update(s);
394 return;
395 }
396 break;;
397
398 case 3:
399 switch (offset) {
400 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
401
402
403 return;
404 case 8: case 9:
405
406 return;
407 case 12:
408 s->ercv = value & 0x1f;
409 case 13:
410
411 return;
412 }
413 break;
414 }
415 cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
416 s->bank, (int)offset);
417}
418
419static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
420{
421 smc91c111_state *s = (smc91c111_state *)opaque;
422
423 if (offset == 14) {
424 return s->bank;
425 }
426 if (offset == 15)
427 return 0x33;
428 switch (s->bank) {
429 case 0:
430 switch (offset) {
431 case 0:
432 return s->tcr & 0xff;
433 case 1:
434 return s->tcr >> 8;
435 case 2:
436 return 0;
437 case 3:
438 return 0x40;
439 case 4:
440 return s->rcr & 0xff;
441 case 5:
442 return s->rcr >> 8;
443 case 6:
444 case 7:
445
446 return 0;
447 case 8:
448 return NUM_PACKETS;
449 case 9:
450 {
451 int i;
452 int n;
453 n = 0;
454 for (i = 0; i < NUM_PACKETS; i++) {
455 if (s->allocated & (1 << i))
456 n++;
457 }
458 return n;
459 }
460 case 10: case 11:
461
462 return 0;
463 }
464 break;
465
466 case 1:
467 switch (offset) {
468 case 0:
469 return s->cr & 0xff;
470 case 1:
471 return s->cr >> 8;
472 case 2: case 3:
473
474 return 0;
475 case 4: case 5: case 6: case 7: case 8: case 9:
476 return s->macaddr[offset - 4];
477 case 10:
478 return s->gpr & 0xff;
479 case 11:
480 return s->gpr >> 8;
481 case 12:
482 return s->ctr & 0xff;
483 case 13:
484 return s->ctr >> 8;
485 }
486 break;
487
488 case 2:
489 switch (offset) {
490 case 0: case 1:
491 return 0;
492 case 2:
493 return s->packet_num;
494 case 3:
495 return s->tx_alloc;
496 case 4:
497 if (s->tx_fifo_done_len == 0)
498 return 0x80;
499 else
500 return s->tx_fifo_done[0];
501 case 5:
502 if (s->rx_fifo_len == 0)
503 return 0x80;
504 else
505 return s->rx_fifo[0];
506 case 6:
507 return s->ptr & 0xff;
508 case 7:
509 return (s->ptr >> 8) & 0xf7;
510 case 8: case 9: case 10: case 11:
511 {
512 int p;
513 int n;
514
515 if (s->ptr & 0x8000)
516 n = s->rx_fifo[0];
517 else
518 n = s->packet_num;
519 p = s->ptr & 0x07ff;
520 if (s->ptr & 0x4000) {
521 s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
522 } else {
523 p += (offset & 3);
524 }
525 return s->data[n][p];
526 }
527 case 12:
528 return s->int_level;
529 case 13:
530 return s->int_mask;
531 }
532 break;
533
534 case 3:
535 switch (offset) {
536 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
537
538
539 return 0;
540 case 8:
541
542 return 0x30;
543 case 9:
544 return 0x33;
545 case 10:
546 return 0x91;
547 case 11:
548 return 0x33;
549 case 12:
550 return s->ercv;
551 case 13:
552 return 0;
553 }
554 break;
555 }
556 cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
557 s->bank, (int)offset);
558 return 0;
559}
560
561static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
562 uint32_t value)
563{
564 smc91c111_writeb(opaque, offset, value & 0xff);
565 smc91c111_writeb(opaque, offset + 1, value >> 8);
566}
567
568static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
569 uint32_t value)
570{
571
572
573 if (offset != 0xc)
574 smc91c111_writew(opaque, offset, value & 0xffff);
575 smc91c111_writew(opaque, offset + 2, value >> 16);
576}
577
578static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
579{
580 uint32_t val;
581 val = smc91c111_readb(opaque, offset);
582 val |= smc91c111_readb(opaque, offset + 1) << 8;
583 return val;
584}
585
586static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
587{
588 uint32_t val;
589 val = smc91c111_readw(opaque, offset);
590 val |= smc91c111_readw(opaque, offset + 2) << 16;
591 return val;
592}
593
594static int smc91c111_can_receive(void *opaque)
595{
596 smc91c111_state *s = (smc91c111_state *)opaque;
597
598 if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
599 return 1;
600 if (s->allocated == (1 << NUM_PACKETS) - 1)
601 return 0;
602 return 1;
603}
604
605static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
606{
607 smc91c111_state *s = (smc91c111_state *)opaque;
608 int status;
609 int packetsize;
610 uint32_t crc;
611 int packetnum;
612 uint8_t *p;
613
614 if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
615 return;
616
617
618 if (size < 64)
619 packetsize = 64;
620 else
621 packetsize = (size & ~1);
622 packetsize += 6;
623 crc = (s->rcr & RCR_STRIP_CRC) == 0;
624 if (crc)
625 packetsize += 4;
626
627 if (packetsize > 2048)
628 return;
629 packetnum = smc91c111_allocate_packet(s);
630 if (packetnum == 0x80)
631 return;
632 s->rx_fifo[s->rx_fifo_len++] = packetnum;
633
634 p = &s->data[packetnum][0];
635
636 status = 0;
637 if (size > 1518)
638 status |= RS_TOOLONG;
639 if (size & 1)
640 status |= RS_ODDFRAME;
641 *(p++) = status & 0xff;
642 *(p++) = status >> 8;
643 *(p++) = packetsize & 0xff;
644 *(p++) = packetsize >> 8;
645 memcpy(p, buf, size & ~1);
646 p += (size & ~1);
647
648 if (size < 64) {
649 int pad;
650
651 if (size & 1)
652 *(p++) = buf[size - 1];
653 pad = 64 - size;
654 memset(p, 0, pad);
655 p += pad;
656 size = 64;
657 }
658
659
660
661
662 if (crc) {
663 crc = crc32(~0, buf, size);
664 *(p++) = crc & 0xff; crc >>= 8;
665 *(p++) = crc & 0xff; crc >>= 8;
666 *(p++) = crc & 0xff; crc >>= 8;
667 *(p++) = crc & 0xff; crc >>= 8;
668 }
669 if (size & 1) {
670 *(p++) = buf[size - 1];
671 *(p++) = 0x60;
672 } else {
673 *(p++) = 0;
674 *(p++) = 0x40;
675 }
676
677 s->int_level |= INT_RCV;
678 smc91c111_update(s);
679}
680
681static CPUReadMemoryFunc *smc91c111_readfn[] = {
682 smc91c111_readb,
683 smc91c111_readw,
684 smc91c111_readl
685};
686
687static CPUWriteMemoryFunc *smc91c111_writefn[] = {
688 smc91c111_writeb,
689 smc91c111_writew,
690 smc91c111_writel
691};
692
693void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
694{
695 smc91c111_state *s;
696 int iomemtype;
697
698 qemu_check_nic_model(nd, "smc91c111");
699
700 s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
701 iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
702 smc91c111_writefn, s);
703 cpu_register_physical_memory(base, 16, iomemtype);
704 s->irq = irq;
705 memcpy(s->macaddr, nd->macaddr, 6);
706
707 smc91c111_reset(s);
708
709 s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
710 smc91c111_receive, smc91c111_can_receive, s);
711 qemu_format_nic_info_str(s->vc, s->macaddr);
712
713}
714