sim: two way IPC working
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Sun, 4 Mar 2012 18:17:03 +0000 (19:17 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Sun, 4 Mar 2012 18:17:03 +0000 (19:17 +0100)
migen/sim/ipc.py
vpi/ipc.c [new file with mode: 0644]
vpi/ipc.h [new file with mode: 0644]

index ad89ce11134d65bf029256cff213a3311ef73ec8..7e80fc860195cba00e6e0ce0a4f56fc217578e07 100644 (file)
@@ -10,6 +10,14 @@ class Message:
                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 @@ message_classes = [MessageTick, MessageGo, MessageWrite, MessageRead, MessageRea
 #
 
 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 @@ class Initiator:
                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)
diff --git a/vpi/ipc.c b/vpi/ipc.c
new file mode 100644 (file)
index 0000000..9b3e529
--- /dev/null
+++ b/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;
+}
diff --git a/vpi/ipc.h b/vpi/ipc.h
new file mode 100644 (file)
index 0000000..ba07ede
--- /dev/null
+++ b/vpi/ipc.h
@@ -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 */