1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
// license:BSD-3-Clause
// copyright-holders:Carl, Miodrag Milanovic
#include "emu.h"
#include "dinetwork.h"
#include "osdnet.h"
#include <algorithm>
device_network_interface::device_network_interface(const machine_config &mconfig, device_t &device, u32 bandwidth, u32 mtu)
: device_interface(device, "network")
, m_poll_timer(nullptr)
, m_send_timer(nullptr)
, m_recv_timer(nullptr)
{
// Convert to Mibps to Bps
m_bandwidth = bandwidth << (20 - 3);
m_mtu = mtu;
m_intf = -1;
m_loopback_control = false;
}
device_network_interface::~device_network_interface()
{
}
void device_network_interface::interface_post_start()
{
m_poll_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::poll_device), this));
m_send_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::send_complete), this));
m_recv_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::recv_complete), this));
device().save_item(NAME(m_loopback_control));
}
void device_network_interface::interface_post_load()
{
if (!m_dev)
m_poll_timer->reset();
else if (!m_loopback_control && !m_recv_timer->enabled())
start_net_device();
else
stop_net_device();
}
int device_network_interface::send(u8 *buf, int len, int fcs)
{
// TODO: enable this check when other devices implement delayed transmit
//if (m_send_timer->enabled())
//throw emu_fatalerror("%s(%s): attempted to transmit while transmit already in progress", device().shortname(), device().tag());
int result = 0;
if (m_loopback_control)
{
// loop data back to receiver
result = recv_start_cb(buf, len);
if (result)
{
// schedule receive complete callback
m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth), result);
}
}
else if (m_dev)
{
// send the data (excluding fcs)
result = m_dev->send(buf, len - fcs);
if (result)
result += fcs;
}
// schedule transmit complete callback
m_send_timer->adjust(attotime::from_ticks(len, m_bandwidth), result);
return result;
}
TIMER_CALLBACK_MEMBER(device_network_interface::poll_device)
{
m_dev->poll();
}
void device_network_interface::start_net_device()
{
// Set device polling time to transfer time for one MTU
m_dev->start();
const attotime interval = attotime::from_hz(m_bandwidth / m_mtu);
m_poll_timer->adjust(attotime::zero, 0, interval);
}
void device_network_interface::stop_net_device()
{
m_poll_timer->reset();
m_dev->stop();
}
TIMER_CALLBACK_MEMBER(device_network_interface::send_complete)
{
send_complete_cb(param);
}
void device_network_interface::recv_cb(u8 *buf, int len)
{
if (m_recv_timer->enabled())
throw emu_fatalerror("%s(%s): attempted to receive while receive already in progress", device().shortname(), device().tag());
int result = 0;
// process the received data
if (!m_loopback_control)
result = recv_start_cb(buf, len);
if (result)
{
// stop receiving more data from the network
if (m_dev)
stop_net_device();
// schedule receive complete callback
m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth), result);
}
}
TIMER_CALLBACK_MEMBER(device_network_interface::recv_complete)
{
recv_complete_cb(param);
// start receiving data from the network again
if (m_dev && !m_loopback_control)
start_net_device();
}
void device_network_interface::set_mac(const u8 *mac)
{
std::copy_n(mac, std::size(m_mac), std::begin(m_mac));
}
void device_network_interface::set_interface(int id)
{
if (m_dev)
stop_net_device();
m_dev.reset(open_netdev(id, *this));
if (m_dev)
{
if (!m_loopback_control)
start_net_device();
}
else
{
device().logerror("Network interface %d not found\n", id);
id = -1;
}
m_intf = id;
}
void device_network_interface::set_loopback(bool loopback)
{
if (m_loopback_control == loopback)
return;
m_loopback_control = loopback;
if (m_dev)
{
if (loopback)
stop_net_device();
else if (!m_recv_timer->enabled())
start_net_device();
}
}
|