1 /*
2 * Copyright (C) 2005-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: A simple ethernet controller, for the test machines
29 *
30 * Basic "ethernet" network device. This is a simple test device which can
31 * be used to send and receive packets to/from a simulated ethernet network.
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "cpu.h"
39 #include "device.h"
40 #include "emul.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "misc.h"
44 #include "net.h"
45
46 #include "testmachine/dev_ether.h"
47
48
49 #define DEV_ETHER_TICK_SHIFT 14
50
51 struct ether_data {
52 struct nic_data nic;
53
54 unsigned char buf[DEV_ETHER_BUFFER_SIZE];
55 unsigned char mac[6];
56
57 int status;
58 int packet_len;
59
60 struct interrupt irq;
61 };
62
63
DEVICE_TICK(ether)64 DEVICE_TICK(ether)
65 {
66 struct ether_data *d = (struct ether_data *) extra;
67 int r = 0;
68
69 d->status &= ~DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE;
70 if (cpu->machine->emul->net != NULL)
71 r = net_ethernet_rx_avail(cpu->machine->emul->net, &d->nic);
72 if (r)
73 d->status |= DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE;
74
75 if (d->status)
76 INTERRUPT_ASSERT(d->irq);
77 else
78 INTERRUPT_DEASSERT(d->irq);
79 }
80
81
DEVICE_ACCESS(ether_buf)82 DEVICE_ACCESS(ether_buf)
83 {
84 struct ether_data *d = (struct ether_data *) extra;
85
86 if (writeflag == MEM_WRITE)
87 memcpy(d->buf + relative_addr, data, len);
88 else
89 memcpy(data, d->buf + relative_addr, len);
90
91 return 1;
92 }
93
94
DEVICE_ACCESS(ether)95 DEVICE_ACCESS(ether)
96 {
97 struct ether_data *d = (struct ether_data *) extra;
98 uint64_t idata = 0, odata = 0;
99 unsigned char *incoming_ptr;
100 int incoming_len;
101
102 if (writeflag == MEM_WRITE)
103 idata = memory_readmax64(cpu, data, len);
104
105 /* Note: relative_addr + DEV_ETHER_BUFFER_SIZE to get the same
106 offsets as in the header file: */
107
108 switch (relative_addr + DEV_ETHER_BUFFER_SIZE) {
109
110 case DEV_ETHER_STATUS:
111 if (writeflag == MEM_READ) {
112 odata = d->status;
113 d->status = 0;
114 INTERRUPT_DEASSERT(d->irq);
115 } else
116 fatal("[ ether: WARNING: write to status ]\n");
117 break;
118
119 case DEV_ETHER_PACKETLENGTH:
120 if (writeflag == MEM_READ)
121 odata = d->packet_len;
122 else {
123 if ((int64_t)idata < 0) {
124 fatal("[ ether: ERROR: packet len too"
125 " short (%i bytes) ]\n", (int)idata);
126 idata = (uint64_t) -1;
127 }
128 if (idata > DEV_ETHER_BUFFER_SIZE) {
129 fatal("[ ether: ERROR: packet len too"
130 " large (%i bytes) ]\n", (int)idata);
131 idata = DEV_ETHER_BUFFER_SIZE;
132 }
133 d->packet_len = idata;
134 }
135 break;
136
137 case DEV_ETHER_COMMAND:
138 if (writeflag == MEM_READ) {
139 fatal("[ ether: WARNING: read from command ]\n");
140 break;
141 }
142
143 /* Write: */
144 switch (idata) {
145
146 case DEV_ETHER_COMMAND_RX: /* Receive: */
147 if (cpu->machine->emul->net == NULL)
148 fatal("[ ether: RECEIVE but no net? ]\n");
149 else {
150 d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED;
151 if (net_ethernet_rx(cpu->machine->emul->net,
152 &d->nic, &incoming_ptr, &incoming_len)) {
153 d->status |=
154 DEV_ETHER_STATUS_PACKET_RECEIVED;
155 if (incoming_len>DEV_ETHER_BUFFER_SIZE)
156 incoming_len =
157 DEV_ETHER_BUFFER_SIZE;
158 memcpy(d->buf, incoming_ptr,
159 incoming_len);
160 free(incoming_ptr);
161 d->packet_len = incoming_len;
162 }
163 }
164 dev_ether_tick(cpu, d);
165 break;
166
167 case DEV_ETHER_COMMAND_TX: /* Send */
168 if (cpu->machine->emul->net == NULL)
169 fatal("[ ether: SEND but no net? ]\n");
170 else
171 net_ethernet_tx(cpu->machine->emul->net,
172 &d->nic, d->buf, d->packet_len);
173 d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED;
174 dev_ether_tick(cpu, d);
175 break;
176
177 default:fatal("[ ether: UNIMPLEMENTED command 0x"
178 "%02x ]\n", idata);
179 cpu->running = 0;
180 }
181 break;
182
183 case DEV_ETHER_MAC:
184 if (writeflag == MEM_READ) {
185 fatal("[ ether: read of MAC is not allowed! ]\n");
186 } else {
187 // Write out the MAC address to the address given.
188 cpu->memory_rw(cpu, cpu->mem, idata, d->nic.mac_address,
189 6, MEM_WRITE, CACHE_NONE);
190 }
191 break;
192
193 default:if (writeflag == MEM_WRITE) {
194 fatal("[ ether: unimplemented write to "
195 "offset 0x%x: data=0x%x ]\n", (int)
196 relative_addr, (int)idata);
197 } else {
198 fatal("[ ether: unimplemented read from "
199 "offset 0x%x ]\n", (int)relative_addr);
200 }
201 }
202
203 if (writeflag == MEM_READ)
204 memory_writemax64(cpu, data, len, odata);
205
206 return 1;
207 }
208
209
DEVINIT(ether)210 DEVINIT(ether)
211 {
212 struct ether_data *d;
213 size_t nlen;
214 char *n1, *n2;
215 char tmp[50];
216
217 CHECK_ALLOCATION(d = (struct ether_data *) malloc(sizeof(struct ether_data)));
218 memset(d, 0, sizeof(struct ether_data));
219
220 nlen = strlen(devinit->name) + 80;
221 CHECK_ALLOCATION(n1 = (char *) malloc(nlen));
222 CHECK_ALLOCATION(n2 = (char *) malloc(nlen));
223
224 INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
225
226 net_generate_unique_mac(devinit->machine, d->nic.mac_address);
227 snprintf(tmp, sizeof(tmp), "%02x:%02x:%02x:%02x:%02x:%02x",
228 d->nic.mac_address[0], d->nic.mac_address[1],
229 d->nic.mac_address[2], d->nic.mac_address[3],
230 d->nic.mac_address[4], d->nic.mac_address[5]);
231
232 snprintf(n1, nlen, "%s [%s]", devinit->name, tmp);
233 snprintf(n2, nlen, "%s [%s, control]", devinit->name, tmp);
234
235 memory_device_register(devinit->machine->memory, n1, devinit->addr,
236 DEV_ETHER_BUFFER_SIZE, dev_ether_buf_access, (void *)d,
237 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK |
238 DM_READS_HAVE_NO_SIDE_EFFECTS, d->buf);
239 memory_device_register(devinit->machine->memory, n2,
240 devinit->addr + DEV_ETHER_BUFFER_SIZE,
241 DEV_ETHER_LENGTH-DEV_ETHER_BUFFER_SIZE, dev_ether_access, (void *)d,
242 DM_DEFAULT, NULL);
243
244 net_add_nic(devinit->machine->emul->net, &d->nic);
245
246 machine_add_tickfunction(devinit->machine,
247 dev_ether_tick, d, DEV_ETHER_TICK_SHIFT);
248
249 return 1;
250 }
251
252