Permalink
Browse files

sim: two way IPC working

  • Loading branch information...
1 parent 8586daf commit 29859acc34d181442050adf98514021fbad752f2 @sbourdeauducq sbourdeauducq committed Mar 4, 2012
Showing with 196 additions and 13 deletions.
  1. +37 −13 migen/sim/ipc.py
  2. +140 −0 vpi/ipc.c
  3. +19 −0 vpi/ipc.h
View
@@ -10,6 +10,14 @@ def __init__(self, *pvalues):
for parameter, value in zip(self.parameters, pvalues):
assert(isinstance(value, parameter[0]))
setattr(self, parameter[1], value)
+
+ def __str__(self):
+ p = ""
+ for parameter in self.parameters:
+ p += parameter[1] + "=" + str(getattr(self, parameter[1]))
+ if p:
+ p = " " + p
+ return "<" + self.__class__.__name__ + p + ">"
class MessageTick(Message):
code = 0
@@ -21,11 +29,11 @@ class MessageGo(Message):
class MessageWrite(Message):
code = 2
- parameters = [(str, "signal"), (int, "value")]
+ parameters = [(str, "name"), (int, "value")]
class MessageRead(Message):
code = 3
- parameters = [(str, "signal")]
+ parameters = [(str, "name")]
class MessageReadReply(Message):
code = 4
@@ -38,16 +46,21 @@ class MessageReadReply(Message):
#
def _pack_int(v):
- # TODO
- return []
+ p = []
+ while v != 0:
+ p.append(v & 0xff)
+ v >>= 8
+ p.insert(0, len(p))
+ return p
def _pack_str(v):
- # TODO
- return []
+ p = [ord(c) for c in v]
+ p.append(0)
+ return p
def _pack(message):
r = [message.code]
- for p, t in message.parameters:
+ for t, p in message.parameters:
value = getattr(message, p)
assert(isinstance(value, t))
if t == int:
@@ -63,19 +76,28 @@ def _pack(message):
#
def _unpack_int(i):
- # TODO
- return 0
+ v = 0
+ power = 1
+ nchunks = next(i)
+ for j in range(nchunks):
+ v += power*next(i)
+ power *= 256
+ return v
def _unpack_str(i):
- # TODO
- return ""
+ v = ""
+ c = next(i)
+ while c:
+ v += chr(c)
+ c = next(i)
+ return v
def _unpack(message):
i = iter(message)
code = next(i)
msgclass = next(filter(lambda x: x.code == code, message_classes))
pvalues = []
- for p, t in msgclass.parameters:
+ for t, p in msgclass.parameters:
if t == int:
v = _unpack_int(i)
elif t == str:
@@ -113,8 +135,10 @@ def send(self, message):
self.conn.send(_pack(message))
def recv(self):
- maxlen = 4096
+ maxlen = 2048
packet = self.conn.recv(maxlen)
+ if len(packet) < 1:
+ return None
if len(packet) >= maxlen:
raise PacketTooLarge
return _unpack(packet)
View
140 vpi/ipc.c
@@ -0,0 +1,140 @@
+#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>
+
+#include "ipc.h"
+
+struct ipc_softc {
+ int socket;
+ go_handler h_go;
+ write_handler h_write;
+ read_handler h_read;
+ void *user;
+};
+
+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;
+ struct sockaddr_un addr;
+
+ sc = malloc(sizeof(struct ipc_softc));
+ if(!sc) return NULL;
+
+ sc->h_go = h_go;
+ sc->h_write = h_write;
+ sc->h_read = h_read;
+ sc->user = user;
+
+ sc->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if(sc->socket < 0) {
+ free(sc);
+ return NULL;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, sockaddr);
+ if(connect(sc->socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
+ close(sc->socket);
+ free(sc);
+ return NULL;
+ }
+
+ return sc;
+}
+
+void ipc_destroy(struct ipc_softc *sc)
+{
+ close(sc->socket);
+ free(sc);
+}
+
+enum {
+ MESSAGE_TICK = 0,
+ MESSAGE_GO,
+ MESSAGE_WRITE,
+ MESSAGE_READ,
+ MESSAGE_READ_REPLY
+};
+
+#define MAX_LEN 2048
+
+int ipc_receive(struct ipc_softc *sc)
+{
+ char buffer[MAX_LEN];
+ ssize_t l;
+ int i;
+
+ l = recv(sc->socket, buffer, MAX_LEN, 0);
+ if((l <= 0) || (l >= MAX_LEN))
+ return 0;
+
+ i = 0;
+ switch(buffer[i++]) {
+ case MESSAGE_GO:
+ assert(l == 1);
+ return sc->h_go(sc->user);
+ case MESSAGE_WRITE: {
+ char *name;
+ int nchunks;
+ unsigned char *chunks;
+
+ name = &buffer[i];
+ i += strlen(name) + 1;
+ assert(i < l);
+ nchunks = buffer[i++];
+ assert(i + nchunks == l);
+ chunks = (unsigned char *)&buffer[i];
+
+ return sc->h_write(name, nchunks, chunks, sc->user);
+ }
+ case MESSAGE_READ: {
+ char *name;
+
+ name = &buffer[i];
+ i += strlen(name) + 1;
+ assert(i == l);
+
+ return sc->h_read(name, sc->user);
+ }
+ default:
+ return 0;
+ }
+}
+
+int ipc_tick(struct ipc_softc *sc)
+{
+ char c;
+ ssize_t l;
+
+ c = MESSAGE_TICK;
+ l = send(sc->socket, &c, 1, 0);
+ if(l != 1)
+ return 0;
+ return 1;
+}
+
+int ipc_read_reply(struct ipc_softc *sc, int nchunks, const unsigned char *chunks)
+{
+ int len;
+ char buffer[MAX_LEN];
+ ssize_t l;
+
+ len = nchunks + 2;
+ assert(len < MAX_LEN);
+ assert(nchunks < 256);
+
+ buffer[0] = MESSAGE_READ_REPLY;
+ buffer[1] = nchunks;
+ memcpy(&buffer[2], chunks, nchunks);
+
+ l = send(sc->socket, buffer, len, 0);
+ if(l != len)
+ return 0;
+ return 1;
+}
View
@@ -0,0 +1,19 @@
+#ifndef __IPC_H
+#define __IPC_H
+
+struct ipc_softc;
+
+typedef int(*go_handler)(void *);
+typedef int(*write_handler)(char *, int, const unsigned char *, void *);
+typedef int(*read_handler)(char *, void *);
+
+struct ipc_softc *ipc_connect(const char *sockaddr,
+ go_handler h_go, write_handler h_write, read_handler h_read, void *user);
+void ipc_destroy(struct ipc_softc *sc);
+
+int ipc_receive(struct ipc_softc *sc);
+
+int ipc_tick(struct ipc_softc *sc);
+int ipc_read_reply(struct ipc_softc *sc, int nchunks, const unsigned char *value);
+
+#endif /* __IPC_H */

0 comments on commit 29859ac

Please sign in to comment.