Skip to content

Commit fe6eef7

Browse files
cr1901sbourdeauducq
authored andcommittedMay 9, 2015
Windows simulation support
1 parent 99fb0d4 commit fe6eef7

File tree

4 files changed

+210
-37
lines changed

4 files changed

+210
-37
lines changed
 

Diff for: ‎migen/sim/generic.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import warnings
2+
import sys
23

34
from migen.fhdl.std import *
45
from migen.fhdl.structure import _Fragment
@@ -25,6 +26,9 @@ def __init__(self, vcd_name=None, vcd_level=1,
2526
self.ios = {cd.clk, cd.rst}
2627

2728
def get(self, sockaddr):
29+
if sys.platform == "win32":
30+
sockaddr = sockaddr[0] # Get the IP address only
31+
2832
template1 = """`timescale 1ns / 1ps
2933
3034
module {top_name}();
@@ -83,7 +87,12 @@ def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocke
8387
if sim_runner is None:
8488
sim_runner = icarus.Runner()
8589
self.top_level = top_level
86-
self.ipc = Initiator(sockaddr)
90+
if sys.platform == "win32":
91+
sockaddr = ("127.0.0.1", 50007)
92+
self.ipc = Initiator(sockaddr)
93+
else:
94+
self.ipc = Initiator(sockaddr)
95+
8796
self.sim_runner = sim_runner
8897

8998
c_top = self.top_level.get(sockaddr)
@@ -217,3 +226,4 @@ def __exit__(self, type, value, traceback):
217226
def run_simulation(fragment, ncycles=None, vcd_name=None, **kwargs):
218227
with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(**kwargs)) as s:
219228
s.run(ncycles)
229+

Diff for: ‎migen/sim/ipc.py

+58-14
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
import socket
55
import os
6+
import sys
7+
import struct
8+
69

710
#
811
# Message classes
912
#
1013

11-
1214
class Int32(int):
1315
pass
1416

@@ -55,11 +57,11 @@ class MessageReadReply(Message):
5557

5658
message_classes = [MessageTick, MessageGo, MessageWrite, MessageRead, MessageReadReply]
5759

60+
5861
#
5962
# Packing
6063
#
6164

62-
6365
def _pack_int(v):
6466
if v == 0:
6567
p = [1, 0]
@@ -78,6 +80,11 @@ def _pack_str(v):
7880
return p
7981

8082

83+
def _pack_int16(v):
84+
return [v & 0xff,
85+
(v & 0xff00) >> 8]
86+
87+
8188
def _pack_int32(v):
8289
return [
8390
v & 0xff,
@@ -100,13 +107,16 @@ def _pack(message):
100107
r += _pack_int32(value)
101108
else:
102109
raise TypeError
110+
if sys.platform == "win32":
111+
size = _pack_int16(len(r) + 2) # size specifier adds to size
112+
r = size + r
103113
return bytes(r)
104114

115+
105116
#
106117
# Unpacking
107118
#
108119

109-
110120
def _unpack_int(i, nchunks=None):
111121
v = 0
112122
power = 1
@@ -144,20 +154,23 @@ def _unpack(message):
144154
pvalues.append(v)
145155
return msgclass(*pvalues)
146156

157+
147158
#
148159
# I/O
149160
#
150161

151-
152162
class PacketTooLarge(Exception):
153163
pass
154164

155165

156166
class Initiator:
157167
def __init__(self, sockaddr):
158168
self.sockaddr = sockaddr
159-
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
160-
self._cleanup_file()
169+
if sys.platform == "win32":
170+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
171+
else:
172+
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
173+
self._cleanup_file()
161174
self.socket.bind(self.sockaddr)
162175
self.socket.listen(1)
163176

@@ -175,18 +188,49 @@ def send(self, message):
175188

176189
def recv(self):
177190
maxlen = 2048
178-
packet = self.conn.recv(maxlen)
179-
if len(packet) < 1:
180-
return None
181-
if len(packet) >= maxlen:
182-
raise PacketTooLarge
191+
if sys.platform == "win32":
192+
packet = self.conn.recv(maxlen)
193+
if len(packet) < 1:
194+
return None
195+
if len(packet) >= maxlen:
196+
raise PacketTooLarge
197+
expected_size = struct.unpack("<H", packet[:2])[0]
198+
199+
# If full packet wasn't received, keep waiting!
200+
if len(packet) < expected_size:
201+
packet_frag = self.conn.recv(maxlen)
202+
packet += packet_frag
203+
if len(packet_frag) < 1:
204+
return None
205+
if len(packet) >= maxlen:
206+
raise PacketTooLarge
207+
208+
# Discard the length from the packet - it's not needed anymore.
209+
packet = packet[2:]
210+
else:
211+
packet = self.conn.recv(maxlen)
212+
if len(packet) < 1:
213+
return None
214+
if len(packet) >= maxlen:
215+
raise PacketTooLarge
183216
return _unpack(packet)
184217

185218
def close(self):
186219
if hasattr(self, "conn"):
187220
self.conn.shutdown(socket.SHUT_RDWR)
188221
self.conn.close()
189222
if hasattr(self, "socket"):
190-
self.socket.shutdown(socket.SHUT_RDWR)
191-
self.socket.close()
192-
self._cleanup_file()
223+
if sys.platform == "win32":
224+
# self.socket.shutdown(socket.SHUT_RDWR)
225+
# Fails with WinError 10057:
226+
# A request to send or receive data was disallowed because the
227+
# socket is not connected and (when sending on a datagram
228+
# socket using a sendto call) no address was supplied
229+
# This error will cascade into WinError 10038, where
230+
# Simulator.__exit__ didn't finish cleaning up and left an
231+
# invalid socket.
232+
self.socket.close()
233+
else:
234+
self.socket.shutdown(socket.SHUT_RDWR)
235+
self.socket.close()
236+
self._cleanup_file()

Diff for: ‎vpi/Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ INSTDIR = $(shell iverilog-vpi --install-dir)
22

33
CFLAGS = -Wall -O2 $(CFLAGS_$@)
44
VPI_CFLAGS := $(shell iverilog-vpi --cflags)
5+
# Define the below flags for a Windows build.
6+
# Make sure to run iverilog-vpi with -mingw and -ivl options if necessary!
7+
# i.e. iverilog-vpi -mingw=C:\msys64\mingw32 -ivl=C:\msys64\mingw32
8+
# MINGW_FLAGS=-lWs2_32
59

610
OBJ=ipc.o main.o
711

@@ -11,7 +15,7 @@ all: migensim.vpi
1115
$(CC) $(CFLAGS) $(VPI_CFLAGS) -c $(INCDIRS) -o $@ $<
1216

1317
migensim.vpi: $(OBJ)
14-
iverilog-vpi --name=migensim $^
18+
iverilog-vpi $(MINGW_FLAGS) --name=migensim $^
1519

1620
install: migensim.vpi
1721
install -m755 -t $(INSTDIR) $^

Diff for: ‎vpi/ipc.c

+136-21
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@
55

66
#include <assert.h>
77
#include <sys/types.h>
8-
#include <sys/socket.h>
9-
#include <sys/un.h>
108
#include <unistd.h>
119
#include <stdio.h>
1210
#include <string.h>
1311
#include <stdlib.h>
1412

13+
#ifdef _WIN32
14+
#include <winsock2.h>
15+
#include <ws2tcpip.h>
16+
#define WIN_SOCKET_PORT "50007"
17+
#else
18+
#include <sys/socket.h>
19+
#include <sys/un.h>
20+
#endif
21+
22+
1523
#include "ipc.h"
1624

1725
struct ipc_softc {
@@ -26,37 +34,75 @@ struct ipc_softc *ipc_connect(const char *sockaddr,
2634
go_handler h_go, write_handler h_write, read_handler h_read, void *user)
2735
{
2836
struct ipc_softc *sc;
37+
#ifdef _WIN32
38+
struct addrinfo hints, *my_addrinfo;
39+
WSADATA wsaData;
40+
#else
2941
struct sockaddr_un addr;
30-
42+
#endif
43+
3144
sc = malloc(sizeof(struct ipc_softc));
3245
if(!sc) return NULL;
33-
46+
3447
sc->h_go = h_go;
3548
sc->h_write = h_write;
3649
sc->h_read = h_read;
3750
sc->user = user;
38-
51+
52+
#ifdef _WIN32
53+
/* Initialize Winsock. */
54+
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
55+
free(sc);
56+
return NULL;
57+
}
58+
59+
memset(&hints, 0, sizeof(hints));
60+
hints.ai_family = AF_INET;
61+
hints.ai_socktype = SOCK_STREAM;
62+
hints.ai_protocol = IPPROTO_TCP;
63+
64+
if(getaddrinfo(sockaddr, WIN_SOCKET_PORT, NULL, &my_addrinfo) != 0) {
65+
free(sc);
66+
return NULL;
67+
}
68+
69+
sc->socket = socket(AF_INET, SOCK_STREAM, 0);
70+
if(sc->socket < 0) {
71+
free(sc);
72+
return NULL;
73+
}
74+
75+
if(connect(sc->socket, my_addrinfo->ai_addr, my_addrinfo->ai_addrlen) != 0) {
76+
close(sc->socket);
77+
free(sc);
78+
return NULL;
79+
}
80+
#else
3981
sc->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
4082
if(sc->socket < 0) {
4183
free(sc);
4284
return NULL;
4385
}
44-
86+
4587
addr.sun_family = AF_UNIX;
4688
strcpy(addr.sun_path, sockaddr);
4789
if(connect(sc->socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
4890
close(sc->socket);
4991
free(sc);
5092
return NULL;
5193
}
52-
94+
#endif
95+
5396
return sc;
5497
}
5598

5699
void ipc_destroy(struct ipc_softc *sc)
57100
{
58101
close(sc->socket);
59102
free(sc);
103+
#ifdef _WIN32
104+
WSACleanup();
105+
#endif
60106
}
61107

62108
enum {
@@ -77,26 +123,69 @@ enum {
77123
int ipc_receive(struct ipc_softc *sc)
78124
{
79125
unsigned char buffer[MAX_LEN];
80-
ssize_t l;
126+
ssize_t l = 0;
81127
int i;
82-
128+
#ifdef _WIN32
129+
int expected_num;
130+
int received_num = 0;
131+
#endif
132+
133+
#ifdef _WIN32
134+
/* Initial recv. Includes a length identifier so that we wait
135+
* until a full message is received. The length of the message
136+
* includes the length identifier. */
137+
while(received_num < 2) {
138+
/* Ensure we wait to get the packet length,
139+
* which requires two bytes, before continuing. */
140+
received_num = recv(sc->socket, (char *)&buffer[l], \
141+
(MAX_LEN - received_num), 0);
142+
l += received_num;
143+
144+
if(received_num == 0)
145+
return 2;
146+
if((received_num < 0) || (received_num >= MAX_LEN) || \
147+
(l >= MAX_LEN))
148+
return 0;
149+
}
150+
151+
expected_num = ((buffer[1] << 8) | (buffer[0]));
152+
while(l < expected_num) {
153+
/* received_num will never exceed MAX_LEN, unless
154+
* recv is broken. */
155+
received_num = recv(sc->socket, (char *)&buffer[l], \
156+
(MAX_LEN - received_num), 0);
157+
l += received_num;
158+
159+
if(received_num == 0)
160+
return 2;
161+
if((received_num < 0) || (received_num >= MAX_LEN) || \
162+
(l >= MAX_LEN))
163+
return 0;
164+
} /* l is assumed to have the message length
165+
* in the message unpacking code. */
166+
i = 2; /* Skip the length identifier. */
167+
#else
168+
/* On Unix, SOCK_SEQPACKET will take care of ensuring message
169+
* boundaries are satisfied. */
83170
l = recv(sc->socket, buffer, MAX_LEN, 0);
84171
if(l == 0)
85172
return 2;
86173
if((l < 0) || (l >= MAX_LEN))
87174
return 0;
88-
89-
i = 0;
175+
i = 0; /* No length identifier, so we care about the entire buffer */
176+
#endif
177+
90178
switch(buffer[i++]) {
91179
case MESSAGE_GO:
92-
assert(l == 1);
180+
assert((l - i) == 0);
181+
93182
return sc->h_go(sc->user);
94183
case MESSAGE_WRITE: {
95184
char *name;
96185
int nchunks;
97186
unsigned char *chunks;
98187
unsigned int chunk_index;
99-
188+
100189
name = (char *)&buffer[i];
101190
i += strlen(name) + 1;
102191
assert((i+4) < l);
@@ -105,18 +194,18 @@ int ipc_receive(struct ipc_softc *sc)
105194
nchunks = buffer[i++];
106195
assert(i + nchunks == l);
107196
chunks = (unsigned char *)&buffer[i];
108-
197+
109198
return sc->h_write(name, chunk_index, nchunks, chunks, sc->user);
110199
}
111200
case MESSAGE_READ: {
112201
char *name;
113202
unsigned int name_index;
114-
203+
115204
name = (char *)&buffer[i];
116205
i += strlen(name) + 1;
117206
assert((i+4) == l);
118207
name_index = buffer[i] | buffer[i+1] << 8 | buffer[i+2] << 16 | buffer[i+3] << 24;
119-
208+
120209
return sc->h_read(name, name_index, sc->user);
121210
}
122211
default:
@@ -126,13 +215,26 @@ int ipc_receive(struct ipc_softc *sc)
126215

127216
int ipc_tick(struct ipc_softc *sc)
128217
{
129-
char c;
130218
ssize_t l;
131-
219+
220+
#ifdef _WIN32
221+
char c[3];
222+
223+
c[0] = 3;
224+
c[1] = 0;
225+
c[2] = MESSAGE_TICK;
226+
l = send(sc->socket, c, 3, 0);
227+
if(l != 3)
228+
return 0;
229+
#else
230+
char c;
231+
132232
c = MESSAGE_TICK;
133233
l = send(sc->socket, &c, 1, 0);
134234
if(l != 1)
135235
return 0;
236+
#endif
237+
136238
return 1;
137239
}
138240

@@ -141,17 +243,30 @@ int ipc_read_reply(struct ipc_softc *sc, int nchunks, const unsigned char *chunk
141243
int len;
142244
char buffer[MAX_LEN];
143245
ssize_t l;
144-
246+
247+
#ifdef _WIN32
248+
len = nchunks + 4;
249+
assert(len < MAX_LEN);
250+
assert(nchunks < 256);
251+
252+
buffer[0] = len & 0xFF;
253+
buffer[1] = (0xFF00 & len) >> 8;
254+
buffer[2] = MESSAGE_READ_REPLY;
255+
buffer[3] = nchunks;
256+
memcpy(&buffer[4], chunks, nchunks);
257+
#else
145258
len = nchunks + 2;
146259
assert(len < MAX_LEN);
147260
assert(nchunks < 256);
148-
261+
149262
buffer[0] = MESSAGE_READ_REPLY;
150263
buffer[1] = nchunks;
151264
memcpy(&buffer[2], chunks, nchunks);
152-
265+
#endif
266+
153267
l = send(sc->socket, buffer, len, 0);
154268
if(l != len)
155269
return 0;
156270
return 1;
157271
}
272+

0 commit comments

Comments
 (0)
Please sign in to comment.