Windows simulation support
This commit is contained in:
parent
99fb0d4619
commit
fe6eef7069
|
@ -1,4 +1,5 @@
|
|||
import warnings
|
||||
import sys
|
||||
|
||||
from migen.fhdl.std import *
|
||||
from migen.fhdl.structure import _Fragment
|
||||
|
@ -25,6 +26,9 @@ class TopLevel:
|
|||
self.ios = {cd.clk, cd.rst}
|
||||
|
||||
def get(self, sockaddr):
|
||||
if sys.platform == "win32":
|
||||
sockaddr = sockaddr[0] # Get the IP address only
|
||||
|
||||
template1 = """`timescale 1ns / 1ps
|
||||
|
||||
module {top_name}();
|
||||
|
@ -83,7 +87,12 @@ class Simulator:
|
|||
if sim_runner is None:
|
||||
sim_runner = icarus.Runner()
|
||||
self.top_level = top_level
|
||||
self.ipc = Initiator(sockaddr)
|
||||
if sys.platform == "win32":
|
||||
sockaddr = ("127.0.0.1", 50007)
|
||||
self.ipc = Initiator(sockaddr)
|
||||
else:
|
||||
self.ipc = Initiator(sockaddr)
|
||||
|
||||
self.sim_runner = sim_runner
|
||||
|
||||
c_top = self.top_level.get(sockaddr)
|
||||
|
@ -217,3 +226,4 @@ class Simulator:
|
|||
def run_simulation(fragment, ncycles=None, vcd_name=None, **kwargs):
|
||||
with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(**kwargs)) as s:
|
||||
s.run(ncycles)
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
|
||||
import socket
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
||||
|
||||
#
|
||||
# Message classes
|
||||
#
|
||||
|
||||
|
||||
class Int32(int):
|
||||
pass
|
||||
|
||||
|
@ -55,11 +57,11 @@ class MessageReadReply(Message):
|
|||
|
||||
message_classes = [MessageTick, MessageGo, MessageWrite, MessageRead, MessageReadReply]
|
||||
|
||||
|
||||
#
|
||||
# Packing
|
||||
#
|
||||
|
||||
|
||||
def _pack_int(v):
|
||||
if v == 0:
|
||||
p = [1, 0]
|
||||
|
@ -78,6 +80,11 @@ def _pack_str(v):
|
|||
return p
|
||||
|
||||
|
||||
def _pack_int16(v):
|
||||
return [v & 0xff,
|
||||
(v & 0xff00) >> 8]
|
||||
|
||||
|
||||
def _pack_int32(v):
|
||||
return [
|
||||
v & 0xff,
|
||||
|
@ -100,13 +107,16 @@ def _pack(message):
|
|||
r += _pack_int32(value)
|
||||
else:
|
||||
raise TypeError
|
||||
if sys.platform == "win32":
|
||||
size = _pack_int16(len(r) + 2) # size specifier adds to size
|
||||
r = size + r
|
||||
return bytes(r)
|
||||
|
||||
|
||||
#
|
||||
# Unpacking
|
||||
#
|
||||
|
||||
|
||||
def _unpack_int(i, nchunks=None):
|
||||
v = 0
|
||||
power = 1
|
||||
|
@ -144,11 +154,11 @@ def _unpack(message):
|
|||
pvalues.append(v)
|
||||
return msgclass(*pvalues)
|
||||
|
||||
|
||||
#
|
||||
# I/O
|
||||
#
|
||||
|
||||
|
||||
class PacketTooLarge(Exception):
|
||||
pass
|
||||
|
||||
|
@ -156,8 +166,11 @@ class PacketTooLarge(Exception):
|
|||
class Initiator:
|
||||
def __init__(self, sockaddr):
|
||||
self.sockaddr = sockaddr
|
||||
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
|
||||
self._cleanup_file()
|
||||
if sys.platform == "win32":
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
else:
|
||||
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
|
||||
self._cleanup_file()
|
||||
self.socket.bind(self.sockaddr)
|
||||
self.socket.listen(1)
|
||||
|
||||
|
@ -175,11 +188,31 @@ class Initiator:
|
|||
|
||||
def recv(self):
|
||||
maxlen = 2048
|
||||
packet = self.conn.recv(maxlen)
|
||||
if len(packet) < 1:
|
||||
return None
|
||||
if len(packet) >= maxlen:
|
||||
raise PacketTooLarge
|
||||
if sys.platform == "win32":
|
||||
packet = self.conn.recv(maxlen)
|
||||
if len(packet) < 1:
|
||||
return None
|
||||
if len(packet) >= maxlen:
|
||||
raise PacketTooLarge
|
||||
expected_size = struct.unpack("<H", packet[:2])[0]
|
||||
|
||||
# If full packet wasn't received, keep waiting!
|
||||
if len(packet) < expected_size:
|
||||
packet_frag = self.conn.recv(maxlen)
|
||||
packet += packet_frag
|
||||
if len(packet_frag) < 1:
|
||||
return None
|
||||
if len(packet) >= maxlen:
|
||||
raise PacketTooLarge
|
||||
|
||||
# Discard the length from the packet - it's not needed anymore.
|
||||
packet = packet[2:]
|
||||
else:
|
||||
packet = self.conn.recv(maxlen)
|
||||
if len(packet) < 1:
|
||||
return None
|
||||
if len(packet) >= maxlen:
|
||||
raise PacketTooLarge
|
||||
return _unpack(packet)
|
||||
|
||||
def close(self):
|
||||
|
@ -187,6 +220,17 @@ class Initiator:
|
|||
self.conn.shutdown(socket.SHUT_RDWR)
|
||||
self.conn.close()
|
||||
if hasattr(self, "socket"):
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
self.socket.close()
|
||||
self._cleanup_file()
|
||||
if sys.platform == "win32":
|
||||
# self.socket.shutdown(socket.SHUT_RDWR)
|
||||
# Fails with WinError 10057:
|
||||
# A request to send or receive data was disallowed because the
|
||||
# socket is not connected and (when sending on a datagram
|
||||
# socket using a sendto call) no address was supplied
|
||||
# This error will cascade into WinError 10038, where
|
||||
# Simulator.__exit__ didn't finish cleaning up and left an
|
||||
# invalid socket.
|
||||
self.socket.close()
|
||||
else:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
self.socket.close()
|
||||
self._cleanup_file()
|
||||
|
|
|
@ -2,6 +2,10 @@ INSTDIR = $(shell iverilog-vpi --install-dir)
|
|||
|
||||
CFLAGS = -Wall -O2 $(CFLAGS_$@)
|
||||
VPI_CFLAGS := $(shell iverilog-vpi --cflags)
|
||||
# Define the below flags for a Windows build.
|
||||
# Make sure to run iverilog-vpi with -mingw and -ivl options if necessary!
|
||||
# i.e. iverilog-vpi -mingw=C:\msys64\mingw32 -ivl=C:\msys64\mingw32
|
||||
# MINGW_FLAGS=-lWs2_32
|
||||
|
||||
OBJ=ipc.o main.o
|
||||
|
||||
|
@ -11,7 +15,7 @@ all: migensim.vpi
|
|||
$(CC) $(CFLAGS) $(VPI_CFLAGS) -c $(INCDIRS) -o $@ $<
|
||||
|
||||
migensim.vpi: $(OBJ)
|
||||
iverilog-vpi --name=migensim $^
|
||||
iverilog-vpi $(MINGW_FLAGS) --name=migensim $^
|
||||
|
||||
install: migensim.vpi
|
||||
install -m755 -t $(INSTDIR) $^
|
||||
|
|
127
vpi/ipc.c
127
vpi/ipc.c
|
@ -5,13 +5,21 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define WIN_SOCKET_PORT "50007"
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "ipc.h"
|
||||
|
||||
struct ipc_softc {
|
||||
|
@ -26,7 +34,12 @@ struct ipc_softc *ipc_connect(const char *sockaddr,
|
|||
go_handler h_go, write_handler h_write, read_handler h_read, void *user)
|
||||
{
|
||||
struct ipc_softc *sc;
|
||||
#ifdef _WIN32
|
||||
struct addrinfo hints, *my_addrinfo;
|
||||
WSADATA wsaData;
|
||||
#else
|
||||
struct sockaddr_un addr;
|
||||
#endif
|
||||
|
||||
sc = malloc(sizeof(struct ipc_softc));
|
||||
if(!sc) return NULL;
|
||||
|
@ -36,6 +49,35 @@ struct ipc_softc *ipc_connect(const char *sockaddr,
|
|||
sc->h_read = h_read;
|
||||
sc->user = user;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Initialize Winsock. */
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
free(sc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
if(getaddrinfo(sockaddr, WIN_SOCKET_PORT, NULL, &my_addrinfo) != 0) {
|
||||
free(sc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sc->socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(sc->socket < 0) {
|
||||
free(sc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(connect(sc->socket, my_addrinfo->ai_addr, my_addrinfo->ai_addrlen) != 0) {
|
||||
close(sc->socket);
|
||||
free(sc);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
sc->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
if(sc->socket < 0) {
|
||||
free(sc);
|
||||
|
@ -49,6 +91,7 @@ struct ipc_softc *ipc_connect(const char *sockaddr,
|
|||
free(sc);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
@ -57,6 +100,9 @@ void ipc_destroy(struct ipc_softc *sc)
|
|||
{
|
||||
close(sc->socket);
|
||||
free(sc);
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
enum {
|
||||
|
@ -77,19 +123,62 @@ enum {
|
|||
int ipc_receive(struct ipc_softc *sc)
|
||||
{
|
||||
unsigned char buffer[MAX_LEN];
|
||||
ssize_t l;
|
||||
ssize_t l = 0;
|
||||
int i;
|
||||
#ifdef _WIN32
|
||||
int expected_num;
|
||||
int received_num = 0;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Initial recv. Includes a length identifier so that we wait
|
||||
* until a full message is received. The length of the message
|
||||
* includes the length identifier. */
|
||||
while(received_num < 2) {
|
||||
/* Ensure we wait to get the packet length,
|
||||
* which requires two bytes, before continuing. */
|
||||
received_num = recv(sc->socket, (char *)&buffer[l], \
|
||||
(MAX_LEN - received_num), 0);
|
||||
l += received_num;
|
||||
|
||||
if(received_num == 0)
|
||||
return 2;
|
||||
if((received_num < 0) || (received_num >= MAX_LEN) || \
|
||||
(l >= MAX_LEN))
|
||||
return 0;
|
||||
}
|
||||
|
||||
expected_num = ((buffer[1] << 8) | (buffer[0]));
|
||||
while(l < expected_num) {
|
||||
/* received_num will never exceed MAX_LEN, unless
|
||||
* recv is broken. */
|
||||
received_num = recv(sc->socket, (char *)&buffer[l], \
|
||||
(MAX_LEN - received_num), 0);
|
||||
l += received_num;
|
||||
|
||||
if(received_num == 0)
|
||||
return 2;
|
||||
if((received_num < 0) || (received_num >= MAX_LEN) || \
|
||||
(l >= MAX_LEN))
|
||||
return 0;
|
||||
} /* l is assumed to have the message length
|
||||
* in the message unpacking code. */
|
||||
i = 2; /* Skip the length identifier. */
|
||||
#else
|
||||
/* On Unix, SOCK_SEQPACKET will take care of ensuring message
|
||||
* boundaries are satisfied. */
|
||||
l = recv(sc->socket, buffer, MAX_LEN, 0);
|
||||
if(l == 0)
|
||||
return 2;
|
||||
if((l < 0) || (l >= MAX_LEN))
|
||||
return 0;
|
||||
i = 0; /* No length identifier, so we care about the entire buffer */
|
||||
#endif
|
||||
|
||||
i = 0;
|
||||
switch(buffer[i++]) {
|
||||
case MESSAGE_GO:
|
||||
assert(l == 1);
|
||||
assert((l - i) == 0);
|
||||
|
||||
return sc->h_go(sc->user);
|
||||
case MESSAGE_WRITE: {
|
||||
char *name;
|
||||
|
@ -126,13 +215,26 @@ int ipc_receive(struct ipc_softc *sc)
|
|||
|
||||
int ipc_tick(struct ipc_softc *sc)
|
||||
{
|
||||
char c;
|
||||
ssize_t l;
|
||||
|
||||
#ifdef _WIN32
|
||||
char c[3];
|
||||
|
||||
c[0] = 3;
|
||||
c[1] = 0;
|
||||
c[2] = MESSAGE_TICK;
|
||||
l = send(sc->socket, c, 3, 0);
|
||||
if(l != 3)
|
||||
return 0;
|
||||
#else
|
||||
char c;
|
||||
|
||||
c = MESSAGE_TICK;
|
||||
l = send(sc->socket, &c, 1, 0);
|
||||
if(l != 1)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -142,6 +244,17 @@ int ipc_read_reply(struct ipc_softc *sc, int nchunks, const unsigned char *chunk
|
|||
char buffer[MAX_LEN];
|
||||
ssize_t l;
|
||||
|
||||
#ifdef _WIN32
|
||||
len = nchunks + 4;
|
||||
assert(len < MAX_LEN);
|
||||
assert(nchunks < 256);
|
||||
|
||||
buffer[0] = len & 0xFF;
|
||||
buffer[1] = (0xFF00 & len) >> 8;
|
||||
buffer[2] = MESSAGE_READ_REPLY;
|
||||
buffer[3] = nchunks;
|
||||
memcpy(&buffer[4], chunks, nchunks);
|
||||
#else
|
||||
len = nchunks + 2;
|
||||
assert(len < MAX_LEN);
|
||||
assert(nchunks < 256);
|
||||
|
@ -149,9 +262,11 @@ int ipc_read_reply(struct ipc_softc *sc, int nchunks, const unsigned char *chunk
|
|||
buffer[0] = MESSAGE_READ_REPLY;
|
||||
buffer[1] = nchunks;
|
||||
memcpy(&buffer[2], chunks, nchunks);
|
||||
#endif
|
||||
|
||||
l = send(sc->socket, buffer, len, 0);
|
||||
if(l != len)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue