Simulator will be rewritten

This commit is contained in:
Sebastien Bourdeauducq 2015-09-05 15:07:00 -06:00
parent dec2e23fc7
commit f1dc008d32
9 changed files with 0 additions and 1126 deletions

View File

View File

@ -1,229 +0,0 @@
import warnings
import sys
from migen.fhdl.std import *
from migen.fhdl.structure import _Fragment
from migen.fhdl import verilog
from migen.sim.ipc import *
from migen.sim import icarus
class TopLevel:
def __init__(self, vcd_name=None, vcd_level=1,
top_name="top", dut_type="dut", dut_name="dut",
cd_name="sys", clk_period=10):
self.vcd_name = vcd_name
self.vcd_level = vcd_level
self.top_name = top_name
self.dut_type = dut_type
self.dut_name = dut_name
self._cd_name = cd_name
self._clk_period = clk_period
cd = ClockDomain(self._cd_name)
self.clock_domains = [cd]
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}();
reg {clk_name};
reg {rst_name};
initial begin
{rst_name} <= 1'b1;
@(posedge {clk_name});
{rst_name} <= 1'b0;
end
always begin
{clk_name} <= 1'b0;
#{hclk_period};
{clk_name} <= 1'b1;
#{hclk_period};
end
{dut_type} {dut_name}(
.{rst_name}({rst_name}),
.{clk_name}({clk_name})
);
initial $migensim_connect("{sockaddr}");
always @(posedge {clk_name}) $migensim_tick;
"""
template2 = """
initial begin
$dumpfile("{vcd_name}");
$dumpvars({vcd_level}, {dut_name});
end
"""
r = template1.format(top_name=self.top_name,
dut_type=self.dut_type,
dut_name=self.dut_name,
clk_name=self._cd_name + "_clk",
rst_name=self._cd_name + "_rst",
hclk_period=str(self._clk_period/2),
sockaddr=sockaddr)
if self.vcd_name is not None:
r += template2.format(vcd_name=self.vcd_name,
vcd_level=str(self.vcd_level),
dut_name=self.dut_name)
r += "\nendmodule"
return r
class Simulator:
def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
if not isinstance(fragment, _Fragment):
fragment = fragment.get_fragment()
if top_level is None:
top_level = TopLevel()
if sim_runner is None:
sim_runner = icarus.Runner()
self.top_level = top_level
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)
fragment = fragment + _Fragment(clock_domains=top_level.clock_domains)
c_fragment = verilog.convert(fragment,
ios=self.top_level.ios,
name=self.top_level.dut_type,
**vopts)
self.namespace = c_fragment.ns
self.cycle_counter = -1
self.sim_runner = sim_runner
self.sim_runner.start(c_top, c_fragment)
self.ipc.accept()
reply = self.ipc.recv()
assert(isinstance(reply, MessageTick))
self.sim_functions = fragment.sim
self.active_sim_functions = set(f for f in fragment.sim if not hasattr(f, "passive") or not f.passive)
self.unreferenced = {}
def run(self, ncycles=None):
counter = 0
if self.active_sim_functions:
if ncycles is None:
def continue_simulation():
return bool(self.active_sim_functions)
else:
def continue_simulation():
return self.active_sim_functions and counter < ncycles
else:
if ncycles is None:
raise ValueError("No active simulation function present - must specify ncycles to end simulation")
def continue_simulation():
return counter < ncycles
while continue_simulation():
self.cycle_counter += 1
counter += 1
self.ipc.send(MessageGo())
reply = self.ipc.recv()
assert(isinstance(reply, MessageTick))
del_list = []
for s in self.sim_functions:
try:
s(self)
except StopSimulation:
del_list.append(s)
for s in del_list:
self.sim_functions.remove(s)
try:
self.active_sim_functions.remove(s)
except KeyError:
pass
def get_unreferenced(self, item, index):
try:
return self.unreferenced[(item, index)]
except KeyError:
if isinstance(item, Memory):
try:
init = item.init[index]
except (TypeError, IndexError):
init = 0
else:
init = item.reset
self.unreferenced[(item, index)] = init
return init
def rd(self, item, index=0):
try:
name = self.top_level.top_name + "." \
+ self.top_level.dut_name + "." \
+ self.namespace.get_name(item)
self.ipc.send(MessageRead(name, Int32(index)))
reply = self.ipc.recv()
assert(isinstance(reply, MessageReadReply))
value = reply.value
except KeyError:
value = self.get_unreferenced(item, index)
if isinstance(item, Memory):
signed = False
nbits = item.width
else:
signed = item.signed
nbits = flen(item)
value = value & (2**nbits - 1)
if signed and (value & 2**(nbits - 1)):
value -= 2**nbits
return value
def wr(self, item, value, index=0):
if isinstance(item, Memory):
nbits = item.width
else:
nbits = flen(item)
if value < 0:
value += 2**nbits
assert(value >= 0 and value < 2**nbits)
try:
name = self.top_level.top_name + "." \
+ self.top_level.dut_name + "." \
+ self.namespace.get_name(item)
self.ipc.send(MessageWrite(name, Int32(index), value))
except KeyError:
self.unreferenced[(item, index)] = value
def __del__(self):
if hasattr(self, "ipc"):
warnings.warn("call Simulator.close() to clean up "
"or use it as a contextmanager", DeprecationWarning)
self.close()
def close(self):
self.ipc.close()
self.sim_runner.close()
del self.ipc
del self.sim_runner
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
def run_simulation(fragment, ncycles=None, vcd_name=None, **kwargs):
with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(**kwargs)) as s:
s.run(ncycles)

View File

@ -1,43 +0,0 @@
# Copyright (C) 2012 Vermeer Manufacturing Co.
# License: GPLv3 with additional permissions (see README).
import subprocess
import os
import time
class Runner:
def __init__(self, options=None, extra_files=None, top_file="migensim_top.v", dut_file="migensim_dut.v", vvp_file=None, keep_files=False):
if extra_files is None: extra_files = []
if vvp_file is None: vvp_file = dut_file + "vp"
if options is None: options = []
self.options = options
self.extra_files = extra_files
self.top_file = top_file
self.dut_file = dut_file
self.vvp_file = vvp_file
self.data_files = []
self.keep_files = keep_files
def start(self, c_top, c_dut):
with open(self.top_file, "w") as f:
f.write(c_top)
c_dut.write(self.dut_file)
self.data_files += c_dut.data_files.keys()
subprocess.check_call(["iverilog", "-o", self.vvp_file] + self.options + [self.top_file, self.dut_file] + self.extra_files)
self.process = subprocess.Popen(["vvp", "-mmigensim", "-Mvpi", self.vvp_file])
def close(self):
if hasattr(self, "process"):
self.process.terminate()
if self.process.poll() is None:
time.sleep(.1)
self.process.kill()
self.process.wait()
if not self.keep_files:
for f in [self.top_file, self.dut_file, self.vvp_file] + self.data_files:
try:
os.remove(f)
except OSError:
pass
self.data_files.clear()

View File

@ -1,228 +0,0 @@
# Copyright (C) 2012 Vermeer Manufacturing Co.
# License: GPLv3 with additional permissions (see README).
import socket
import os
import sys
import struct
if sys.platform == "win32":
header_len = 2
#
# Message classes
#
class Int32(int):
pass
class Message:
def __init__(self, *pvalues):
for parameter, value in zip(self.parameters, pvalues):
setattr(self, parameter[1], parameter[0](value))
def __str__(self):
p = []
for parameter in self.parameters:
p.append(parameter[1] + "=" + str(getattr(self, parameter[1])))
if p:
pf = " " + " ".join(p)
else:
pf = ""
return "<" + self.__class__.__name__ + pf + ">"
class MessageTick(Message):
code = 0
parameters = []
class MessageGo(Message):
code = 1
parameters = []
class MessageWrite(Message):
code = 2
parameters = [(str, "name"), (Int32, "index"), (int, "value")]
class MessageRead(Message):
code = 3
parameters = [(str, "name"), (Int32, "index")]
class MessageReadReply(Message):
code = 4
parameters = [(int, "value")]
message_classes = [MessageTick, MessageGo, MessageWrite, MessageRead, MessageReadReply]
#
# Packing
#
def _pack_int(v):
if v == 0:
p = [1, 0]
else:
p = []
while v != 0:
p.append(v & 0xff)
v >>= 8
p.insert(0, len(p))
return p
def _pack_str(v):
p = [ord(c) for c in v]
p.append(0)
return p
def _pack_int16(v):
return [v & 0xff,
(v & 0xff00) >> 8]
def _pack_int32(v):
return [
v & 0xff,
(v & 0xff00) >> 8,
(v & 0xff0000) >> 16,
(v & 0xff000000) >> 24
]
def _pack(message):
r = [message.code]
for t, p in message.parameters:
value = getattr(message, p)
assert(isinstance(value, t))
if t == int:
r += _pack_int(value)
elif t == str:
r += _pack_str(value)
elif t == Int32:
r += _pack_int32(value)
else:
raise TypeError
if sys.platform == "win32":
size = _pack_int16(len(r) + header_len)
r = size + r
return bytes(r)
#
# Unpacking
#
def _unpack_int(i, nchunks=None):
v = 0
power = 1
if nchunks is None:
nchunks = next(i)
for j in range(nchunks):
v += power*next(i)
power *= 256
return v
def _unpack_str(i):
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 t, p in msgclass.parameters:
if t == int:
v = _unpack_int(i)
elif t == str:
v = _unpack_str(i)
elif t == Int32:
v = _unpack_int(i, 4)
else:
raise TypeError
pvalues.append(v)
return msgclass(*pvalues)
#
# I/O
#
class PacketTooLarge(Exception):
pass
class Initiator:
def __init__(self, sockaddr):
self.sockaddr = sockaddr
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)
self.ipc_rxbuffer = bytearray()
def _cleanup_file(self):
try:
os.remove(self.sockaddr)
except OSError:
pass
def accept(self):
self.conn, addr = self.socket.accept()
def send(self, message):
self.conn.send(_pack(message))
def recv_packet(self, maxlen):
if sys.platform == "win32":
while len(self.ipc_rxbuffer) < header_len:
self.ipc_rxbuffer += self.conn.recv(maxlen)
packet_len = struct.unpack("<H", self.ipc_rxbuffer[:header_len])[0]
while len(self.ipc_rxbuffer) < packet_len:
self.ipc_rxbuffer += self.conn.recv(maxlen)
packet = self.ipc_rxbuffer[header_len:packet_len]
self.ipc_rxbuffer = self.ipc_rxbuffer[packet_len:]
else:
packet = self.conn.recv(maxlen)
return packet
def recv(self):
maxlen = 2048
packet = self.recv_packet(maxlen)
if len(packet) < 1:
return None
if len(packet) >= maxlen:
raise PacketTooLarge
return _unpack(packet)
def close(self):
if hasattr(self, "conn"):
self.conn.shutdown(socket.SHUT_RDWR)
self.conn.close()
if hasattr(self, "socket"):
if sys.platform == "win32":
# don't shutdown our socket since closing connection
# seems to already have done it. (trigger an error
# otherwise)
self.socket.close()
else:
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
self._cleanup_file()

View File

@ -1,112 +0,0 @@
from migen.fhdl.structure import Signal, StopSimulation
from migen.fhdl.specials import Memory
class MemoryProxy:
def __init__(self, simulator, obj):
self.simulator = simulator
self._simproxy_obj = obj
def __getitem__(self, key):
if isinstance(key, int):
return self.simulator.rd(self._simproxy_obj, key)
else:
start, stop, step = key.indices(self._simproxy_obj.depth)
return [self.simulator.rd(self._simproxy_obj, i) for i in range(start, stop, step)]
def __setitem__(self, key, value):
if isinstance(key, int):
self.simulator.wr(self._simproxy_obj, key, value)
else:
start, stop, step = key.indices(self.__obj.depth)
if len(value) != (stop - start)//step:
raise ValueError
for i, v in zip(range(start, stop, step), value):
self.simulator.wr(self._simproxy_obj, i, v)
class Proxy:
def __init__(self, simulator, obj):
object.__setattr__(self, "simulator", simulator)
object.__setattr__(self, "_simproxy_obj", obj)
def __process_get(self, item):
if isinstance(item, Signal):
return self.simulator.rd(item)
elif isinstance(item, Memory):
return MemoryProxy(self.simulator, item)
else:
return Proxy(self.simulator, item)
def __getattr__(self, name):
return self.__process_get(getattr(self._simproxy_obj, name))
def __setattr__(self, name, value):
item = getattr(self._simproxy_obj, name)
assert(isinstance(item, Signal))
self.simulator.wr(item, value)
def __getitem__(self, key):
return self.__process_get(self._simproxy_obj[key])
def __setitem__(self, key, value):
item = self._simproxy_obj[key]
assert(isinstance(item, Signal))
self.simulator.wr(item, value)
def gen_sim(simg):
gens = dict()
resume_cycle = 0
def do_simulation(s):
nonlocal resume_cycle, gens
if isinstance(s, Proxy):
simulator = s.simulator
else:
simulator = s
if simulator.cycle_counter >= resume_cycle:
try:
gen = gens[simulator]
except KeyError:
gen = simg(s)
gens[simulator] = gen
try:
n = next(gen)
except StopIteration:
del gens[simulator]
raise StopSimulation
else:
if n is None:
n = 1
resume_cycle = simulator.cycle_counter + n
if hasattr(simg, "passive"):
do_simulation.passive = simg.passive
return do_simulation
def proxy_sim(target, simf):
proxies = dict()
def do_simulation(simulator):
nonlocal proxies
try:
proxy = proxies[simulator]
except KeyError:
proxy = Proxy(simulator, target)
proxies[simulator] = proxy
try:
simf(proxy)
except StopSimulation:
del proxies[simulator]
raise
if hasattr(simf, "passive"):
do_simulation.passive = simf.passive
return do_simulation

View File

@ -1,27 +0,0 @@
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
all: migensim.vpi
%.o: %.c
$(CC) $(CFLAGS) $(VPI_CFLAGS) -c $(INCDIRS) -o $@ $<
migensim.vpi: $(OBJ)
iverilog-vpi $(MINGW_FLAGS) --name=migensim $^
install: migensim.vpi
install -m755 -t $(INSTDIR) $^
clean:
rm -f $(OBJ)
rm -f migensim.vpi
.PHONY: install clean

260
vpi/ipc.c
View File

@ -1,260 +0,0 @@
/*
* Copyright (C) 2012 Vermeer Manufacturing Co.
* License: GPLv3 with additional permissions (see README).
*/
#ifdef _WIN32
#define WINVER 0x501
#endif
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include "ipc.h"
struct ipc_softc {
int socket;
go_handler h_go;
write_handler h_write;
read_handler h_read;
void *user;
};
#define MAX_LEN 2048
#ifdef _WIN32
#define HEADER_LEN 2
#define SOCKET_PORT "50007"
unsigned char ipc_rxbuffer[2*MAX_LEN];
int ipc_rxlen;
#else
#define HEADER_LEN 0
#endif
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;
ipc_rxlen = 0;
#else
struct sockaddr_un addr;
#endif
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;
#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, 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);
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;
}
#endif
return sc;
}
void ipc_destroy(struct ipc_softc *sc)
{
close(sc->socket);
free(sc);
#ifdef _WIN32
WSACleanup();
#endif
}
enum {
MESSAGE_TICK = 0,
MESSAGE_GO,
MESSAGE_WRITE,
MESSAGE_READ,
MESSAGE_READ_REPLY
};
static int ipc_receive_packet(struct ipc_softc *sc, unsigned char *buffer) {
#ifdef _WIN32
int len;
int packet_len;
/* ensure we have packet header */
while(ipc_rxlen < HEADER_LEN) {
len = recv(sc->socket, (char *)&ipc_rxbuffer[ipc_rxlen], MAX_LEN, 0);
if(len)
ipc_rxlen += len;
}
/* compute packet length and ensure we have the payload */
packet_len = (ipc_rxbuffer[1] << 8) | ipc_rxbuffer[0];
while(ipc_rxlen < packet_len) {
len = recv(sc->socket, (char *)&ipc_rxbuffer[ipc_rxlen], MAX_LEN, 0);
if(len)
ipc_rxlen += len;
}
/* copy packet to buffer */
memcpy(buffer, ipc_rxbuffer + HEADER_LEN, packet_len - HEADER_LEN);
/* prepare ipc_rxbuffer for next packet */
ipc_rxlen = ipc_rxlen - packet_len;
memcpy(ipc_rxbuffer, ipc_rxbuffer + packet_len, ipc_rxlen);
return packet_len - HEADER_LEN;
#else
return recv(sc->socket, buffer, MAX_LEN, 0);
#endif
}
/*
* 0 -> error
* 1 -> success
* 2 -> graceful shutdown
*/
int ipc_receive(struct ipc_softc *sc)
{
unsigned char buffer[MAX_LEN];
ssize_t l = 0;
int i;
l = ipc_receive_packet(sc, (unsigned char *)&buffer);
if(l == 0)
return 2;
if((l < 0) || (l >= MAX_LEN))
return 0;
i = 0;
switch(buffer[i++]) {
case MESSAGE_GO:
assert((l - i) == 0);
return sc->h_go(sc->user);
case MESSAGE_WRITE: {
char *name;
int nchunks;
unsigned char *chunks;
unsigned int chunk_index;
name = (char *)&buffer[i];
i += strlen(name) + 1;
assert((i+4) < l);
chunk_index = buffer[i] | buffer[i+1] << 8 | buffer[i+2] << 16 | buffer[i+3] << 24;
i += 4;
nchunks = buffer[i++];
assert(i + nchunks == l);
chunks = (unsigned char *)&buffer[i];
return sc->h_write(name, chunk_index, nchunks, chunks, sc->user);
}
case MESSAGE_READ: {
char *name;
unsigned int name_index;
name = (char *)&buffer[i];
i += strlen(name) + 1;
assert((i+4) == l);
name_index = buffer[i] | buffer[i+1] << 8 | buffer[i+2] << 16 | buffer[i+3] << 24;
return sc->h_read(name, name_index, sc->user);
}
default:
return 0;
}
}
int ipc_tick(struct ipc_softc *sc)
{
ssize_t l;
char c[HEADER_LEN + 1];
#ifdef _WIN32
c[0] = 3;
c[1] = 0;
#endif
c[HEADER_LEN + 0] = MESSAGE_TICK;
l = send(sc->socket, c, HEADER_LEN + 1, 0);
if(l != (HEADER_LEN + 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 + HEADER_LEN + 2;
assert(len < MAX_LEN);
assert(nchunks < 256);
#ifdef _WIN32
buffer[0] = len & 0xFF;
buffer[1] = (0xFF00 & len) >> 8;
#endif
buffer[HEADER_LEN + 0] = MESSAGE_READ_REPLY;
buffer[HEADER_LEN + 1] = nchunks;
memcpy(&buffer[HEADER_LEN + 2], chunks, nchunks);
l = send(sc->socket, buffer, len, 0);
if(l != len)
return 0;
return 1;
}

View File

@ -1,24 +0,0 @@
/*
* Copyright (C) 2012 Vermeer Manufacturing Co.
* License: GPLv3 with additional permissions (see README).
*/
#ifndef __IPC_H
#define __IPC_H
struct ipc_softc;
typedef int(*go_handler)(void *);
typedef int(*write_handler)(char *, int, int, const unsigned char *, void *);
typedef int(*read_handler)(char *, int, 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 */

View File

@ -1,203 +0,0 @@
/*
* Copyright (C) 2012 Vermeer Manufacturing Co.
* License: GPLv3 with additional permissions (see README).
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <vpi_user.h>
#include "ipc.h"
struct migensim_softc {
struct ipc_softc *ipc;
int has_go;
};
static int h_go(void *user)
{
struct migensim_softc *sc = (struct migensim_softc *)user;
sc->has_go = 1;
return 1;
}
static s_vpi_time zero_delay = {
.type = vpiSimTime,
.high = 0,
.low = 0
};
static int h_write(char *name, int index, int nchunks, const unsigned char *chunks, void *user)
{
vpiHandle item;
s_vpi_vecval vector[64];
int i;
s_vpi_value value;
item = vpi_handle_by_name(name, NULL);
if(item == NULL) {
fprintf(stderr, "Attempted to write non-existing signal %s\n", name);
return 0;
}
if(vpi_get(vpiType, item) == vpiMemory)
item = vpi_handle_by_index(item, index);
else
assert(index == 0);
assert(nchunks <= 255);
for(i=0;i<64;i++) {
vector[i].aval = 0;
vector[i].bval = 0;
}
for(i=0;i<nchunks;i++)
vector[i/4].aval |= chunks[i] << 8*(i % 4);
value.format = vpiVectorVal;
value.value.vector = vector;
vpi_put_value(item, &value, &zero_delay, vpiInertialDelay);
return 1;
}
static int h_read(char *name, int index, void *user)
{
struct migensim_softc *sc = (struct migensim_softc *)user;
vpiHandle item;
s_vpi_value value;
int size;
int i;
int nvals;
unsigned int vals[64];
int nchunks;
unsigned char chunks[255];
item = vpi_handle_by_name(name, NULL);
if(item == NULL) {
fprintf(stderr, "Attempted to read non-existing signal %s\n", name);
return 0;
}
if(vpi_get(vpiType, item) == vpiMemory)
item = vpi_handle_by_index(item, index);
else
assert(index == 0);
value.format = vpiVectorVal;
vpi_get_value(item, &value);
size = vpi_get(vpiSize, item);
nvals = (size + 31)/32;
assert(nvals <= 64);
for(i=0;i<nvals;i++)
vals[i] = value.value.vector[i].aval & ~value.value.vector[i].bval;
nchunks = (size + 7)/8;
assert(nchunks <= 255);
for(i=0;i<nchunks;i++) {
switch(i % 4) {
case 0:
chunks[i] = vals[i/4] & 0xff;
break;
case 1:
chunks[i] = (vals[i/4] & 0xff00) >> 8;
break;
case 2:
chunks[i] = (vals[i/4] & 0xff0000) >> 16;
break;
case 3:
chunks[i] = (vals[i/4] & 0xff000000) >> 24;
break;
}
}
if(!ipc_read_reply(sc->ipc, nchunks, chunks)) {
perror("ipc_read_reply");
return 0;
}
return 1;
}
static int process_until_go(struct migensim_softc *sc)
{
int r;
sc->has_go = 0;
while(!sc->has_go) {
r = ipc_receive(sc->ipc);
if(r != 1)
return r;
}
return 1;
}
static PLI_INT32 connect_calltf(PLI_BYTE8 *user)
{
struct migensim_softc *sc = (struct migensim_softc *)user;
vpiHandle sys;
vpiHandle argv;
vpiHandle item;
s_vpi_value value;
sys = vpi_handle(vpiSysTfCall, 0);
argv = vpi_iterate(vpiArgument, sys);
item = vpi_scan(argv);
value.format = vpiStringVal;
vpi_get_value(item, &value);
sc->ipc = ipc_connect(value.value.str, h_go, h_write, h_read, sc);
if(sc->ipc == NULL) {
perror("ipc_connect");
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
static PLI_INT32 tick_calltf(PLI_BYTE8 *user)
{
struct migensim_softc *sc = (struct migensim_softc *)user;
int r;
if(!ipc_tick(sc->ipc)) {
perror("ipc_tick");
vpi_control(vpiFinish, 1);
ipc_destroy(sc->ipc);
sc->ipc = NULL;
return 0;
}
r = process_until_go(sc);
if(r != 1) {
vpi_control(vpiFinish, r == 2 ? 0 : 1);
ipc_destroy(sc->ipc);
sc->ipc = NULL;
return 0;
}
return 0;
}
static struct migensim_softc sc;
static void simple_register(const char *tfname, PLI_INT32 (*calltf)(PLI_BYTE8 *))
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = tfname;
tf_data.calltf = calltf;
tf_data.compiletf = NULL;
tf_data.sizetf = 0;
tf_data.user_data = (void *)&sc;
vpi_register_systf(&tf_data);
}
static void migensim_register()
{
simple_register("$migensim_connect", connect_calltf);
simple_register("$migensim_tick", tick_calltf);
}
void (*vlog_startup_routines[])() = {
migensim_register,
0
};