litex/build/sim: introduce new simulator with modules support (thanks lambdaconcept)
This commit is contained in:
parent
6631aa5385
commit
8510b12e93
|
@ -20,6 +20,8 @@ from litedram.core.controller import ControllerSettings
|
||||||
from liteeth.phy.model import LiteEthPHYModel
|
from liteeth.phy.model import LiteEthPHYModel
|
||||||
from liteeth.core.mac import LiteEthMAC
|
from liteeth.core.mac import LiteEthMAC
|
||||||
|
|
||||||
|
from litex.build.sim.config import SimConfig
|
||||||
|
|
||||||
class BaseSoC(SoCSDRAM):
|
class BaseSoC(SoCSDRAM):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
platform = sim.Platform()
|
platform = sim.Platform()
|
||||||
|
@ -92,10 +94,15 @@ def main():
|
||||||
help="enable Ethernet support")
|
help="enable Ethernet support")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
scfg = SimConfig(default_clk="sys_clk")
|
||||||
|
scfg.add_module("serial2console", "serial")
|
||||||
|
if args.with_ethernet:
|
||||||
|
scfg.add_module('ethernet', "eth", args={"interface": "tap1", "ip": "192.168.1.100"})
|
||||||
|
|
||||||
cls = MiniSoC if args.with_ethernet else BaseSoC
|
cls = MiniSoC if args.with_ethernet else BaseSoC
|
||||||
soc = cls(**soc_sdram_argdict(args))
|
soc = cls(**soc_sdram_argdict(args))
|
||||||
builder = Builder(soc, **builder_argdict(args))
|
builder = Builder(soc, **builder_argdict(args))
|
||||||
builder.build()
|
builder.build(sim_config=scfg)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
class SimConfig():
|
||||||
|
def __init__(self, default_clk=None):
|
||||||
|
self.modules = []
|
||||||
|
self.default_clk = default_clk
|
||||||
|
if default_clk:
|
||||||
|
self.add_clocker(default_clk)
|
||||||
|
|
||||||
|
def _format_interfaces(self, interfaces):
|
||||||
|
if not isinstance(interfaces, list):
|
||||||
|
interfaces = [interfaces]
|
||||||
|
new = []
|
||||||
|
for it in interfaces:
|
||||||
|
obj = it
|
||||||
|
if isinstance(it, tuple):
|
||||||
|
name, index = it
|
||||||
|
obj = {"name": name, "index": index}
|
||||||
|
new.append(obj)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def add_clocker(self, clk):
|
||||||
|
self.add_module("clocker", [], clocks=clk, tickfirst=True)
|
||||||
|
|
||||||
|
def add_module(self, name, interfaces, clocks=None, args=None, tickfirst=False):
|
||||||
|
interfaces = self._format_interfaces(interfaces)
|
||||||
|
if clocks:
|
||||||
|
interfaces += self._format_interfaces(clocks)
|
||||||
|
else:
|
||||||
|
interfaces += [self.default_clk]
|
||||||
|
newmod = {
|
||||||
|
"module": name,
|
||||||
|
"interface": interfaces,
|
||||||
|
}
|
||||||
|
if args:
|
||||||
|
newmod.update({"args": args})
|
||||||
|
if tickfirst:
|
||||||
|
newmod.update({"tickfirst": tickfirst})
|
||||||
|
self.modules.append(newmod)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
return json.dumps(self.modules, indent=4)
|
|
@ -0,0 +1,40 @@
|
||||||
|
include variables.mak
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wall -O3 -ggdb
|
||||||
|
LDFLAGS = -lpthread -ljson-c -lm -lstdc++ -ldl -levent
|
||||||
|
|
||||||
|
SRC_DIR ?= .
|
||||||
|
INC_DIR ?= .
|
||||||
|
MOD_DIR = $(SRC_DIR)/modules
|
||||||
|
export OBJ_DIR = $(abspath obj_dir)
|
||||||
|
|
||||||
|
SRCS_SIM_ABSPATH = $(wildcard $(SRC_DIR)/*.c)
|
||||||
|
SRCS_SIM = $(notdir $(SRCS_SIM_ABSPATH))
|
||||||
|
SRCS_SIM_CPP = dut_init.cpp $(SRC_DIR)/veril.cpp
|
||||||
|
OBJS_SIM = $(SRCS_SIM:.c=.o)
|
||||||
|
|
||||||
|
all: modules sim
|
||||||
|
|
||||||
|
mkdir:
|
||||||
|
mkdir -p $(OBJ_DIR)
|
||||||
|
|
||||||
|
$(OBJS_SIM): %.o: $(SRC_DIR)/%.c
|
||||||
|
$(CC) -c $(CFLAGS) -o $(OBJ_DIR)/$@ $<
|
||||||
|
|
||||||
|
.PHONY: sim
|
||||||
|
sim: mkdir $(OBJS_SIM)
|
||||||
|
verilator -Wno-fatal -O3 --cc dut.v --exe \
|
||||||
|
$(SRCS_SIM_CPP) $(OBJS_SIM) \
|
||||||
|
-CFLAGS "$(CFLAGS) -I$(SRC_DIR)" \
|
||||||
|
-LDFLAGS "$(LDFLAGS)" \
|
||||||
|
-trace $(INC_DIR)
|
||||||
|
make -j -C $(OBJ_DIR) -f Vdut.mk Vdut
|
||||||
|
|
||||||
|
.PHONY: modules
|
||||||
|
modules: mkdir
|
||||||
|
$(MAKE) -C $(MOD_DIR)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJ_DIR)
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#ifndef __ERROR_H_
|
||||||
|
#define __ERROR_H_
|
||||||
|
|
||||||
|
#define RC_OK 0
|
||||||
|
#define RC_ERROR -1
|
||||||
|
#define RC_INVARG -2
|
||||||
|
#define RC_NOENMEM -3
|
||||||
|
#define RC_JSERROR -4
|
||||||
|
|
||||||
|
#define eprintf(format, ...) fprintf (stderr, "%s:%d "format, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,366 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "libdylib.h"
|
||||||
|
|
||||||
|
#ifdef LIBDYLIB_CXX
|
||||||
|
using libdylib::dylib_ref;
|
||||||
|
namespace libdylib {
|
||||||
|
#endif
|
||||||
|
struct dylib_data {
|
||||||
|
void *handle;
|
||||||
|
const char *path;
|
||||||
|
bool dyn_path; // true if path should be freed
|
||||||
|
bool freed;
|
||||||
|
bool is_self;
|
||||||
|
};
|
||||||
|
#ifdef LIBDYLIB_CXX
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(const void*, get_handle)(dylib_ref lib)
|
||||||
|
{
|
||||||
|
return lib->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(const char*, get_path)(dylib_ref lib)
|
||||||
|
{
|
||||||
|
return lib->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ERR_MAX_SIZE 2048
|
||||||
|
static char last_err[ERR_MAX_SIZE];
|
||||||
|
static bool last_err_set = 0;
|
||||||
|
static void set_last_error(const char *s)
|
||||||
|
{
|
||||||
|
if (!s)
|
||||||
|
s = "NULL error";
|
||||||
|
last_err_set = 1;
|
||||||
|
strncpy(last_err, s, ERR_MAX_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dylib_ref dylib_ref_alloc (void *handle, const char *path)
|
||||||
|
{
|
||||||
|
if (handle == NULL)
|
||||||
|
return NULL;
|
||||||
|
dylib_ref ref = NULL;
|
||||||
|
ref = (dylib_ref)malloc(sizeof(*ref));
|
||||||
|
ref->handle = handle;
|
||||||
|
ref->path = path;
|
||||||
|
ref->dyn_path = false;
|
||||||
|
ref->freed = false;
|
||||||
|
ref->is_self = false;
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static dylib_ref dylib_ref_alloc_dynamic (void *handle, char *path)
|
||||||
|
{
|
||||||
|
dylib_ref ref = dylib_ref_alloc(handle, path);
|
||||||
|
if (ref == NULL)
|
||||||
|
return NULL;
|
||||||
|
ref->dyn_path = true;
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static void dylib_ref_free (dylib_ref ref)
|
||||||
|
{
|
||||||
|
if (ref == NULL)
|
||||||
|
return;
|
||||||
|
if (ref->freed)
|
||||||
|
return;
|
||||||
|
ref->handle = NULL;
|
||||||
|
if (ref->dyn_path)
|
||||||
|
free((char*)ref->path);
|
||||||
|
ref->freed = true;
|
||||||
|
free((void*)ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void platform_set_last_error();
|
||||||
|
static void *platform_raw_open (const char *path);
|
||||||
|
static void *platform_raw_open_self();
|
||||||
|
static bool platform_raw_close (void *handle);
|
||||||
|
static void *platform_raw_lookup (void *handle, const char *symbol);
|
||||||
|
|
||||||
|
#define check_null_arg(arg, msg, ret) if (arg == NULL) {set_last_error(msg); return ret; }
|
||||||
|
#define check_null_handle(handle, ret) check_null_arg(handle, "NULL library handle", ret)
|
||||||
|
#define check_null_path(path, ret) check_null_arg(path, "NULL library path", ret)
|
||||||
|
|
||||||
|
#if defined(LIBDYLIB_UNIX)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static void platform_set_last_error()
|
||||||
|
{
|
||||||
|
set_last_error(dlerror());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *platform_raw_open (const char *path)
|
||||||
|
{
|
||||||
|
return (void*)dlopen(path, RTLD_LOCAL | RTLD_NOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *platform_raw_open_self()
|
||||||
|
{
|
||||||
|
//return (void*)RTLD_SELF;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool platform_raw_close (void *handle)
|
||||||
|
{
|
||||||
|
return dlclose(handle) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *platform_raw_lookup (void *handle, const char *symbol)
|
||||||
|
{
|
||||||
|
return dlsym(handle, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end LIBDYLIB_UNIX
|
||||||
|
#elif defined(LIBDYLIB_WINDOWS)
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
static void platform_set_last_error()
|
||||||
|
{
|
||||||
|
// Based on http://stackoverflow.com/questions/1387064
|
||||||
|
DWORD code = GetLastError();
|
||||||
|
if (!code)
|
||||||
|
set_last_error(NULL);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LPSTR buf = NULL;
|
||||||
|
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
|
||||||
|
set_last_error((const char*)buf);
|
||||||
|
LocalFree(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *platform_raw_open (const char *path)
|
||||||
|
{
|
||||||
|
return (void*)LoadLibrary(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *platform_raw_open_self()
|
||||||
|
{
|
||||||
|
return (void*)GetModuleHandle(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool platform_raw_close (void *handle)
|
||||||
|
{
|
||||||
|
return FreeLibrary((HMODULE)handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *platform_raw_lookup (void *handle, const char *symbol)
|
||||||
|
{
|
||||||
|
return (void*)GetProcAddress((HMODULE)handle, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end LIBDYLIB_WINDOWS
|
||||||
|
#else
|
||||||
|
#error "unrecognized platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// All platforms
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(dylib_ref, open)(const char *path)
|
||||||
|
{
|
||||||
|
check_null_path(path, NULL);
|
||||||
|
dylib_ref lib = dylib_ref_alloc(platform_raw_open(path), path);
|
||||||
|
if (lib == NULL)
|
||||||
|
platform_set_last_error();
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(dylib_ref, open_self)()
|
||||||
|
{
|
||||||
|
dylib_ref lib = dylib_ref_alloc(platform_raw_open_self(), NULL);
|
||||||
|
lib->is_self = true;
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(bool, close)(dylib_ref lib)
|
||||||
|
{
|
||||||
|
check_null_handle(lib, 0);
|
||||||
|
if (lib->is_self)
|
||||||
|
{
|
||||||
|
dylib_ref_free(lib);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool ret = platform_raw_close((void*)lib->handle);
|
||||||
|
if (!ret)
|
||||||
|
platform_set_last_error();
|
||||||
|
else
|
||||||
|
dylib_ref_free(lib);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(void*, lookup)(dylib_ref lib, const char *symbol)
|
||||||
|
{
|
||||||
|
check_null_handle(lib, NULL);
|
||||||
|
void *ret = platform_raw_lookup((void*)lib->handle, symbol);
|
||||||
|
if (ret == NULL)
|
||||||
|
platform_set_last_error();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(dylib_ref, open_list)(const char *path, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, path);
|
||||||
|
dylib_ref ret = LIBDYLIB_NAME(va_open_list)(path, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(dylib_ref, va_open_list)(const char *path, va_list args)
|
||||||
|
{
|
||||||
|
const char *curpath = path;
|
||||||
|
dylib_ref ret = NULL;
|
||||||
|
while (curpath)
|
||||||
|
{
|
||||||
|
ret = LIBDYLIB_NAME(open)(curpath);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
curpath = va_arg(args, const char*);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *locate_patterns[] =
|
||||||
|
#if defined(LIBDYLIB_APPLE)
|
||||||
|
{"lib%s.dylib", "%s.framework/%s", "%s.dylib", "lib%s.so", "%s.so"}
|
||||||
|
#elif defined(LIBDYLIB_LINUX)
|
||||||
|
{"lib%s.so", "%s.so"}
|
||||||
|
#elif defined(LIBDYLIB_WINDOWS)
|
||||||
|
{"%s.dll", "lib%s.dll"}
|
||||||
|
#else
|
||||||
|
#warning "Falling back to default open_locate patterns"
|
||||||
|
{"lib%s.so", "%s.so"}
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
char *simple_format(const char *pattern, const char *str)
|
||||||
|
{
|
||||||
|
size_t i_in = 0,
|
||||||
|
i_out = 0,
|
||||||
|
len_p = strlen(pattern),
|
||||||
|
len_s = strlen(str),
|
||||||
|
len_out = len_p;
|
||||||
|
{
|
||||||
|
const char *tmp = pattern;
|
||||||
|
while ((tmp = strstr(tmp, "%s")))
|
||||||
|
{
|
||||||
|
len_out += len_s - 2;
|
||||||
|
++tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *out = (char*)malloc((len_out + 1) * sizeof(char));
|
||||||
|
while (i_in < len_p)
|
||||||
|
{
|
||||||
|
if (pattern[i_in] == '%' && pattern[i_in + 1] == 's')
|
||||||
|
{
|
||||||
|
strcpy(out + i_out, str);
|
||||||
|
i_in += 2;
|
||||||
|
i_out += len_s;
|
||||||
|
}
|
||||||
|
else if (pattern[i_in] == '%' && pattern[i_in + 1] == '%')
|
||||||
|
{
|
||||||
|
out[i_out++] = '%';
|
||||||
|
i_in += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out[i_out++] = pattern[i_in++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out[len_out] = 0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(dylib_ref, open_locate)(const char *name)
|
||||||
|
{
|
||||||
|
dylib_ref lib = NULL;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < (sizeof(locate_patterns) / sizeof(locate_patterns[0])); ++i)
|
||||||
|
{
|
||||||
|
char *path = simple_format(locate_patterns[i], name);
|
||||||
|
lib = LIBDYLIB_NAME(open)(path);
|
||||||
|
if (lib != NULL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
if (lib == NULL)
|
||||||
|
lib = LIBDYLIB_NAME(open)(name);
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(bool, bind)(dylib_ref lib, const char *symbol, void **dest)
|
||||||
|
{
|
||||||
|
*dest = LIBDYLIB_NAME(lookup)(lib, symbol);
|
||||||
|
return *dest != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(bool, find)(dylib_ref lib, const char *symbol)
|
||||||
|
{
|
||||||
|
return LIBDYLIB_NAME(lookup)(lib, symbol) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(bool, find_any)(dylib_ref lib, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, lib);
|
||||||
|
bool ret = LIBDYLIB_NAME(va_find_any)(lib, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
LIBDYLIB_DEFINE(bool, va_find_any)(dylib_ref lib, va_list args)
|
||||||
|
{
|
||||||
|
const char *cursym = NULL;
|
||||||
|
bool ret = 0;
|
||||||
|
while (!ret && (cursym = va_arg(args, const char*)))
|
||||||
|
{
|
||||||
|
if (LIBDYLIB_NAME(lookup)(lib, cursym))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
LIBDYLIB_DEFINE(bool, find_all)(dylib_ref lib, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, lib);
|
||||||
|
bool ret = LIBDYLIB_NAME(va_find_all)(lib, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
LIBDYLIB_DEFINE(bool, va_find_all)(dylib_ref lib, va_list args)
|
||||||
|
{
|
||||||
|
const char *cursym = NULL;
|
||||||
|
bool ret = 1;
|
||||||
|
while (ret && (cursym = va_arg(args, const char*)))
|
||||||
|
{
|
||||||
|
if (!LIBDYLIB_NAME(lookup)(lib, cursym))
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(const char*, last_error)()
|
||||||
|
{
|
||||||
|
if (!last_err_set)
|
||||||
|
return NULL;
|
||||||
|
return last_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(int, get_version)()
|
||||||
|
{
|
||||||
|
return LIBDYLIB_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBDYLIB_DEFINE(const char*, get_version_str())
|
||||||
|
{
|
||||||
|
return LIBDYLIB_VERSION_STR;
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
#ifndef LIBDYLIB_H
|
||||||
|
#define LIBDYLIB_H
|
||||||
|
|
||||||
|
#define LIBDYLIB_VERSION 0x020000
|
||||||
|
#define LIBDYLIB_VERSION_STR "2.0.0"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#if !defined(LIBDYLIB_UNIX) && (defined(__APPLE__) || defined(__linux__) || defined(__UNIX__))
|
||||||
|
#define LIBDYLIB_UNIX
|
||||||
|
#elif !defined(LIBDYLIB_WINDOWS) && defined(WIN32)
|
||||||
|
#define LIBDYLIB_WINDOWS
|
||||||
|
#endif
|
||||||
|
#if !defined(LIBDYLIB_UNIX) && !defined(LIBDYLIB_WINDOWS)
|
||||||
|
#error "Could not detect platform - try defining LIBDYLIB_UNIX or LIBDYLIB_WINDOWS appropriately"
|
||||||
|
#endif
|
||||||
|
#if defined(LIBDYLIB_UNIX)
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#ifndef LIBDYLIB_APPLE
|
||||||
|
#define LIBDYLIB_APPLE
|
||||||
|
#endif
|
||||||
|
#elif defined(__linux__) || defined(__linux)
|
||||||
|
#ifndef LIBDYLIB_LINUX
|
||||||
|
#define LIBDYLIB_LINUX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBDYLIB_UNIX
|
||||||
|
#define LIBDYLIB_EXPORT __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
#define LIBDYLIB_EXPORT __declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#ifndef LIBDYLIB_C
|
||||||
|
#define LIBDYLIB_CXX
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef LIBDYLIB_CXX
|
||||||
|
#error "Can't build as C++ with a C compiler"
|
||||||
|
#else
|
||||||
|
#define LIBDYLIB_C
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBDYLIB_C
|
||||||
|
#define LIBDYLIB_NAME(name) libdylib_##name
|
||||||
|
#define LIBDYLIB_DECLARE(type, name) LIBDYLIB_EXPORT type libdylib_##name
|
||||||
|
#define LIBDYLIB_DEFINE(type, name) type libdylib_##name
|
||||||
|
#else
|
||||||
|
#define LIBDYLIB_NAME(name) libdylib::name
|
||||||
|
#define LIBDYLIB_DECLARE(type, name) LIBDYLIB_EXPORT type name
|
||||||
|
#define LIBDYLIB_DEFINE(type, name) type libdylib::name
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBDYLIB_CXX
|
||||||
|
namespace libdylib {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct dylib_data* dylib_ref;
|
||||||
|
LIBDYLIB_DECLARE(const void*, get_handle)(dylib_ref lib);
|
||||||
|
LIBDYLIB_DECLARE(const char*, get_path)(dylib_ref lib);
|
||||||
|
|
||||||
|
// attempt to load a dynamic library from a path
|
||||||
|
// return a library handle or NULL
|
||||||
|
LIBDYLIB_DECLARE(dylib_ref, open)(const char *path);
|
||||||
|
|
||||||
|
// return a handle to the current executable
|
||||||
|
LIBDYLIB_DECLARE(dylib_ref, open_self)();
|
||||||
|
|
||||||
|
// close the specified dynamic library
|
||||||
|
// returns 1 on success, 0 on failure
|
||||||
|
LIBDYLIB_DECLARE(bool, close)(dylib_ref lib);
|
||||||
|
|
||||||
|
// attempt to load a dynamic library from all paths given
|
||||||
|
// return a library handle of the first successfully-loaded library, or NULL if none were successfully loaded
|
||||||
|
// NOTE: the last argument must be NULL
|
||||||
|
LIBDYLIB_DECLARE(dylib_ref, open_list)(const char *path, ...);
|
||||||
|
LIBDYLIB_DECLARE(dylib_ref, va_open_list)(const char *path, va_list args);
|
||||||
|
|
||||||
|
// attempt to load a dynamic library using platform-specific prefixes/suffixes
|
||||||
|
// e.g. open_locate("foo") would attempt to open libfoo.so and foo.so on Linux
|
||||||
|
LIBDYLIB_DECLARE(dylib_ref, open_locate)(const char *name);
|
||||||
|
|
||||||
|
// return the address of a symbol in a library, or NULL if the symbol does not exist
|
||||||
|
LIBDYLIB_DECLARE(void*, lookup)(dylib_ref lib, const char *symbol);
|
||||||
|
|
||||||
|
// set the contents of dest to the result of lookup(lib, symbol) and returns 1,
|
||||||
|
// or set dest to NULL and returns 0 if the symbol was not found
|
||||||
|
LIBDYLIB_DECLARE(bool, bind)(dylib_ref lib, const char *symbol, void **dest);
|
||||||
|
// helper macros - note that dest is a simple pointer, NOT a pointer to a pointer
|
||||||
|
#define LIBDYLIB_BIND(lib, symbol, dest) LIBDYLIB_NAME(bind)(lib, symbol, (void**)&dest)
|
||||||
|
#define LIBDYLIB_BINDNAME(lib, name) LIBDYLIB_BIND(lib, #name, name)
|
||||||
|
|
||||||
|
// check for the existence of a symbol in a library
|
||||||
|
LIBDYLIB_DECLARE(bool, find)(dylib_ref lib, const char *symbol);
|
||||||
|
|
||||||
|
// check for the existence of any or all specified symbols in a library, respectively
|
||||||
|
// NOTE: the last argument must be NULL (0 should not be relied on)
|
||||||
|
LIBDYLIB_DECLARE(bool, find_any)(dylib_ref lib, ...);
|
||||||
|
LIBDYLIB_DECLARE(bool, va_find_any)(dylib_ref lib, va_list args);
|
||||||
|
LIBDYLIB_DECLARE(bool, find_all)(dylib_ref lib, ...);
|
||||||
|
LIBDYLIB_DECLARE(bool, va_find_all)(dylib_ref lib, va_list args);
|
||||||
|
|
||||||
|
// returns the last error message set by libdylib functions, or NULL
|
||||||
|
LIBDYLIB_DECLARE(const char*, last_error)();
|
||||||
|
|
||||||
|
// return compiled version information
|
||||||
|
LIBDYLIB_DECLARE(int, get_version)();
|
||||||
|
LIBDYLIB_DECLARE(const char*, get_version_str)();
|
||||||
|
|
||||||
|
#ifdef LIBDYLIB_CXX
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LIBDYLIB_H */
|
|
@ -0,0 +1,164 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "tinydir.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "libdylib.h"
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define LIBEXT "dll"
|
||||||
|
#else
|
||||||
|
#define LIBEXT "so"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct ext_module_list_s *modlist=NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int lambdasim_register_ext_module(struct ext_module_s *mod)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct ext_module_list_s *ml=NULL;
|
||||||
|
|
||||||
|
if(!mod)
|
||||||
|
{
|
||||||
|
eprintf("Invalid arguments\n");
|
||||||
|
ret=RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ml=( struct ext_module_list_s *)malloc(sizeof( struct ext_module_list_s));
|
||||||
|
if(NULL == ml)
|
||||||
|
{
|
||||||
|
ret = RC_NOENMEM;
|
||||||
|
eprintf("Not enough memory\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(ml, 0, sizeof( struct ext_module_list_s));
|
||||||
|
ml->module = mod;
|
||||||
|
ml->next = modlist;
|
||||||
|
modlist = ml;
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lambdasim_load_ext_modules(struct ext_module_list_s **mlist)
|
||||||
|
{
|
||||||
|
int ret = RC_OK;
|
||||||
|
tinydir_dir dir;
|
||||||
|
tinydir_file file;
|
||||||
|
dylib_ref lib;
|
||||||
|
int (*lambdasim_ext_module_init)(int (*reg)(struct ext_module_s *));
|
||||||
|
char name[100];
|
||||||
|
if (tinydir_open(&dir, "./modules/") == -1)
|
||||||
|
{
|
||||||
|
ret = RC_ERROR;
|
||||||
|
eprintf("Error opening file");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(modlist)
|
||||||
|
{
|
||||||
|
ret=RC_ERROR;
|
||||||
|
eprintf("modules already loaded !\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
while(dir.has_next)
|
||||||
|
{
|
||||||
|
if(-1 == tinydir_readfile(&dir, &file))
|
||||||
|
{
|
||||||
|
ret = RC_ERROR;
|
||||||
|
eprintf("Can't get file \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(file.extension, LIBEXT))
|
||||||
|
{
|
||||||
|
sprintf(name, "./modules/%s", file.name);
|
||||||
|
lib = libdylib_open(name);
|
||||||
|
if(!lib)
|
||||||
|
{
|
||||||
|
ret = RC_ERROR;
|
||||||
|
eprintf("Can't load library %s\n", libdylib_last_error());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!libdylib_find(lib, "lambdasim_ext_module_init"))
|
||||||
|
{
|
||||||
|
ret = RC_ERROR;
|
||||||
|
eprintf("Module has no lambdasim_ext_module_init function\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
LIBDYLIB_BINDNAME(lib, lambdasim_ext_module_init);
|
||||||
|
if(!lambdasim_ext_module_init)
|
||||||
|
{
|
||||||
|
ret = RC_ERROR;
|
||||||
|
eprintf("Can't bind %s\n", libdylib_last_error());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = lambdasim_ext_module_init(lambdasim_register_ext_module);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(-1 == tinydir_next(&dir))
|
||||||
|
{
|
||||||
|
eprintf("Error getting next file\n");
|
||||||
|
ret = RC_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*mlist = modlist;
|
||||||
|
out:
|
||||||
|
tinydir_close(&dir);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lambdasim_find_ext_module(struct ext_module_list_s *first, char *name , struct ext_module_list_s **found)
|
||||||
|
{
|
||||||
|
struct ext_module_list_s *list = NULL;
|
||||||
|
int ret=RC_OK;
|
||||||
|
|
||||||
|
if(!first || !name || !found)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid arg\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(list = first; list; list=list->next)
|
||||||
|
{
|
||||||
|
if(!strcmp(name, list->module->name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
*found = list;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int lambdasim_find_module(struct module_s *first, char *name , struct module_s **found)
|
||||||
|
{
|
||||||
|
struct module_s *list = NULL;
|
||||||
|
int ret=RC_OK;
|
||||||
|
|
||||||
|
if(!first || !name || !found)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid arg\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(list = first; list; list=list->next)
|
||||||
|
{
|
||||||
|
if(!strcmp(name, list->name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
*found = list;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#ifndef __MODULE_H_
|
||||||
|
#define __MODULE_H_
|
||||||
|
|
||||||
|
#include "pads.h"
|
||||||
|
|
||||||
|
struct interface_s {
|
||||||
|
char *name;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct module_s {
|
||||||
|
char *name;
|
||||||
|
struct interface_s *iface;
|
||||||
|
size_t niface;
|
||||||
|
char tickfirst;
|
||||||
|
char *args;
|
||||||
|
struct module_s *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct ext_module_s {
|
||||||
|
char *name;
|
||||||
|
int (*start)(void *);
|
||||||
|
int (*new_sess)(void **, char *);
|
||||||
|
int (*add_pads)(void *, struct pad_list_s *);
|
||||||
|
int (*close)(void*);
|
||||||
|
int (*tick)(void*);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ext_module_list_s {
|
||||||
|
struct ext_module_s *module;
|
||||||
|
struct ext_module_list_s *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int lambdasim_file_to_module_list(char *filename, struct module_s **mod);
|
||||||
|
int lambdasim_load_ext_modules(struct ext_module_list_s **mlist);
|
||||||
|
int lambdasim_find_ext_module(struct ext_module_list_s *first, char *name , struct ext_module_list_s **found);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,14 @@
|
||||||
|
MODULES = ethernet serial2console serial2tcp clocker
|
||||||
|
SHROBJS = $(MODULES:=.so)
|
||||||
|
|
||||||
|
.PHONY: $(MODULES)
|
||||||
|
all: $(MODULES)
|
||||||
|
|
||||||
|
$(MODULES): %:
|
||||||
|
$(MAKE) -C $@
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
for module in $(MODULES); do \
|
||||||
|
$(MAKE) -C $$module $@; \
|
||||||
|
done
|
|
@ -0,0 +1,5 @@
|
||||||
|
include ../variables.mak
|
||||||
|
|
||||||
|
all: $(OBJ_DIR)/clocker.so
|
||||||
|
|
||||||
|
include ../rules.mak
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
struct session_s {
|
||||||
|
char *sys_clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int lambdasim_module_pads_get( struct pad_s *pads, char *name, void **signal)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *sig=NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!pads || !name || !signal)
|
||||||
|
{
|
||||||
|
ret=RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while(pads[i].name)
|
||||||
|
{
|
||||||
|
if(!strcmp(pads[i].name, name))
|
||||||
|
{
|
||||||
|
sig=(void*)pads[i].signal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
*signal=sig;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clocker_start()
|
||||||
|
{
|
||||||
|
printf("Loaded !\n");
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clocker_new(void **sess, char *args)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
|
||||||
|
struct session_s *s=NULL;
|
||||||
|
|
||||||
|
if(!sess)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
s=(struct session_s*)malloc(sizeof(struct session_s));
|
||||||
|
if(!s)
|
||||||
|
{
|
||||||
|
ret=RC_NOENMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(s, 0, sizeof(struct session_s));
|
||||||
|
out:
|
||||||
|
*sess=(void*)s;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clocker_add_pads(void *sess, struct pad_list_s *plist)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
struct pad_s *pads;
|
||||||
|
if(!sess || !plist)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pads = plist->pads;
|
||||||
|
|
||||||
|
if(!strcmp(plist->name, "sys_clk"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
*s->sys_clk=0;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clocker_tick(void *sess)
|
||||||
|
{
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
*s->sys_clk = ~(*s->sys_clk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ext_module_s ext_mod = {
|
||||||
|
"clocker",
|
||||||
|
clocker_start,
|
||||||
|
clocker_new,
|
||||||
|
clocker_add_pads,
|
||||||
|
NULL,
|
||||||
|
clocker_tick
|
||||||
|
};
|
||||||
|
|
||||||
|
int lambdasim_ext_module_init(int (*register_module)(struct ext_module_s *))
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
ret = register_module(&ext_mod);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
include ../variables.mak
|
||||||
|
CFLAGS += -Itapcfg/src/include
|
||||||
|
|
||||||
|
all: $(OBJ_DIR)/ethernet.so
|
||||||
|
|
||||||
|
include ../rules.mak
|
||||||
|
|
||||||
|
OBJS = $(addprefix $(OBJ_DIR)/, ethernet.o tapcfg.o taplog.o)
|
||||||
|
|
||||||
|
$(OBJ_DIR)/ethernet.so: $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^
|
||||||
|
|
||||||
|
$(OBJ_DIR)/tapcfg.o: tapcfg/src/lib/tapcfg.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(OBJ_DIR)/taplog.o: tapcfg/src/lib/taplog.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
|
@ -0,0 +1,314 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#include <event2/listener.h>
|
||||||
|
#include <event2/util.h>
|
||||||
|
#include <event2/event.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
|
#include "tapcfg.h"
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
struct eth_packet_s {
|
||||||
|
char data[2000];
|
||||||
|
size_t len;
|
||||||
|
struct eth_packet_s *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct session_s {
|
||||||
|
char *tx;
|
||||||
|
char *tx_valid;
|
||||||
|
char *tx_ready;
|
||||||
|
char *rx;
|
||||||
|
char *rx_valid;
|
||||||
|
char *rx_ready;
|
||||||
|
char *sys_clk;
|
||||||
|
tapcfg_t *tapcfg;
|
||||||
|
int fd;
|
||||||
|
char databuf[2000];
|
||||||
|
int datalen;
|
||||||
|
char inbuf[2000];
|
||||||
|
int inlen;
|
||||||
|
int insent;
|
||||||
|
struct eth_packet_s *ethpack;
|
||||||
|
struct event *ev;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct event_base *base=NULL;
|
||||||
|
|
||||||
|
int lambdasim_module_get_args( char *args, char *arg, char **val)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
json_object *jsobj=NULL;
|
||||||
|
json_object *obj=NULL;
|
||||||
|
char *value=NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
jsobj = json_tokener_parse(args);
|
||||||
|
if(NULL==jsobj)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error parsing json arg: %s \n", args);
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(!json_object_is_type(jsobj, json_type_object))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Arg must be type object! : %s \n", args);
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
obj=NULL;
|
||||||
|
r = json_object_object_get_ex(jsobj, arg, &obj);
|
||||||
|
if(!r)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not find object: \"%s\" (%s)\n", arg, args);
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
value=strdup(json_object_get_string(obj));
|
||||||
|
|
||||||
|
out:
|
||||||
|
*val = value;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int lambdasim_module_pads_get( struct pad_s *pads, char *name, void **signal)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *sig=NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!pads || !name || !signal)
|
||||||
|
{
|
||||||
|
ret=RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while(pads[i].name)
|
||||||
|
{
|
||||||
|
if(!strcmp(pads[i].name, name))
|
||||||
|
{
|
||||||
|
sig=(void*)pads[i].signal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
*signal=sig;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ethernet_start(void *b)
|
||||||
|
{
|
||||||
|
base=(struct event_base *)b;
|
||||||
|
printf("Loaded eth %p!\n", base);
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void event_handler(int fd, short event, void *arg)
|
||||||
|
{
|
||||||
|
struct session_s *s=(struct session_s*)arg;
|
||||||
|
struct eth_packet_s *ep;
|
||||||
|
struct eth_packet_s *tep;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (event & EV_TIMEOUT) {
|
||||||
|
//printf("timeout\n");
|
||||||
|
} else if (event & EV_READ) {
|
||||||
|
ep = malloc(sizeof(struct eth_packet_s));
|
||||||
|
memset(ep, 0, sizeof(struct eth_packet_s));
|
||||||
|
ep->len = tapcfg_read(s->tapcfg, ep->data, 2000);
|
||||||
|
if(ep->len < 60)
|
||||||
|
{
|
||||||
|
ep->len = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!s->ethpack)
|
||||||
|
{
|
||||||
|
s->ethpack = ep;
|
||||||
|
} else {
|
||||||
|
for(tep=s->ethpack; tep->next; tep=tep->next);
|
||||||
|
tep->next = ep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const char macadr[6] = {0xaa, 0xb6, 0x24, 0x69, 0x77, 0x21};
|
||||||
|
|
||||||
|
static int ethernet_new(void **sess, char *args)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
char *c_tap=NULL;
|
||||||
|
char *c_tap_ip=NULL;
|
||||||
|
struct session_s *s=NULL;
|
||||||
|
struct timeval tv={10, 0};
|
||||||
|
if(!sess)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
s=(struct session_s*)malloc(sizeof(struct session_s));
|
||||||
|
if(!s)
|
||||||
|
{
|
||||||
|
ret=RC_NOENMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(s, 0, sizeof(struct session_s));
|
||||||
|
|
||||||
|
ret = lambdasim_module_get_args(args, "interface", &c_tap);
|
||||||
|
{
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = lambdasim_module_get_args(args, "ip", &c_tap_ip);
|
||||||
|
{
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->tapcfg = tapcfg_init();
|
||||||
|
tapcfg_start(s->tapcfg, c_tap, 0);
|
||||||
|
s->fd = tapcfg_get_fd(s->tapcfg);
|
||||||
|
tapcfg_iface_set_hwaddr(s->tapcfg, macadr, 6);
|
||||||
|
tapcfg_iface_set_ipv4(s->tapcfg, c_tap_ip, 24);
|
||||||
|
tapcfg_iface_set_status(s->tapcfg, TAPCFG_STATUS_ALL_UP);
|
||||||
|
free(c_tap);
|
||||||
|
free(c_tap_ip);
|
||||||
|
printf("FT:%d\n", s->fd);
|
||||||
|
printf("ETHERNET MODULE NEW CALLED\n");
|
||||||
|
|
||||||
|
s->ev = event_new(base, s->fd, EV_READ | EV_PERSIST, event_handler, s);
|
||||||
|
event_add(s->ev, &tv);
|
||||||
|
|
||||||
|
out:
|
||||||
|
*sess=(void*)s;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ethernet_add_pads(void *sess, struct pad_list_s *plist)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
struct pad_s *pads;
|
||||||
|
if(!sess || !plist)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pads = plist->pads;
|
||||||
|
if(!strcmp(plist->name, "eth"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sink_data", (void**)&s->rx);
|
||||||
|
lambdasim_module_pads_get(pads, "sink_valid", (void**)&s->rx_valid);
|
||||||
|
lambdasim_module_pads_get(pads, "sink_ready", (void**)&s->rx_ready);
|
||||||
|
lambdasim_module_pads_get(pads, "source_data", (void**)&s->tx);
|
||||||
|
lambdasim_module_pads_get(pads, "source_valid", (void**)&s->tx_valid);
|
||||||
|
lambdasim_module_pads_get(pads, "source_ready", (void**)&s->tx_ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(plist->name, "sys_clk"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
static int ethernet_tick(void *sess)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
struct eth_packet_s *pep;
|
||||||
|
|
||||||
|
if(*s->sys_clk == 0)
|
||||||
|
{
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*s->tx_ready = 1;
|
||||||
|
if(*s->tx_valid == 1)
|
||||||
|
{
|
||||||
|
c = *s->tx;
|
||||||
|
//printf("%02x ", (unsigned char)c);
|
||||||
|
s->databuf[s->datalen++]=c;
|
||||||
|
} else {
|
||||||
|
if(s->datalen)
|
||||||
|
{
|
||||||
|
//printf("send fini\n");
|
||||||
|
tapcfg_write(s->tapcfg, s->databuf, s->datalen);
|
||||||
|
s->datalen=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*s->rx_valid=0;
|
||||||
|
if(s->inlen)
|
||||||
|
{
|
||||||
|
*s->rx_valid=1;
|
||||||
|
*s->rx = s->inbuf[s->insent++];
|
||||||
|
//printf("%02x ", (unsigned char)*s->rx);
|
||||||
|
//printf("%d", *s->rx_ready);
|
||||||
|
if(s->insent == s->inlen)
|
||||||
|
{
|
||||||
|
//printf("recv fini\n");
|
||||||
|
s->insent =0;
|
||||||
|
s->inlen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(s->ethpack)
|
||||||
|
{
|
||||||
|
memcpy(s->inbuf, s->ethpack->data, s->ethpack->len);
|
||||||
|
s->inlen = s->ethpack->len;
|
||||||
|
pep=s->ethpack->next;
|
||||||
|
free(s->ethpack);
|
||||||
|
s->ethpack=pep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(tapcfg_wait_readable(s->tapcfg, 0))
|
||||||
|
{
|
||||||
|
memset(s->inbuf, 0, 2000);
|
||||||
|
s->inlen = tapcfg_read(s->tapcfg, s->inbuf, 2000);
|
||||||
|
|
||||||
|
if(s->inlen < 60)
|
||||||
|
{
|
||||||
|
s->inlen = 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ext_module_s ext_mod = {
|
||||||
|
"ethernet",
|
||||||
|
ethernet_start,
|
||||||
|
ethernet_new,
|
||||||
|
ethernet_add_pads,
|
||||||
|
NULL,
|
||||||
|
ethernet_tick
|
||||||
|
};
|
||||||
|
|
||||||
|
int lambdasim_ext_module_init(int (*register_module)(struct ext_module_s *))
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
ret = register_module(&ext_mod);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
$(OBJ_DIR)/%.o: %.c
|
||||||
|
$(CC) -c $(CFLAGS) -I../.. -o $@ $<
|
||||||
|
|
||||||
|
$(OBJ_DIR)/%.so: $(OBJ_DIR)/%.o
|
||||||
|
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $<
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ_DIR)/*.o $(OBJ_DIR)/*.so
|
|
@ -0,0 +1,5 @@
|
||||||
|
include ../variables.mak
|
||||||
|
|
||||||
|
all: $(OBJ_DIR)/serial2console.so
|
||||||
|
|
||||||
|
include ../rules.mak
|
|
@ -0,0 +1,208 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <event2/listener.h>
|
||||||
|
#include <event2/util.h>
|
||||||
|
#include <event2/event.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
struct session_s {
|
||||||
|
char *tx;
|
||||||
|
char *tx_valid;
|
||||||
|
char *tx_ready;
|
||||||
|
char *rx;
|
||||||
|
char *rx_valid;
|
||||||
|
char *rx_ready;
|
||||||
|
char *sys_clk;
|
||||||
|
struct event *ev;
|
||||||
|
char databuf[2048];
|
||||||
|
int data_start;
|
||||||
|
int datalen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct event_base *base;
|
||||||
|
static int lambdasim_module_pads_get( struct pad_s *pads, char *name, void **signal)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *sig=NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!pads || !name || !signal)
|
||||||
|
{
|
||||||
|
ret=RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while(pads[i].name)
|
||||||
|
{
|
||||||
|
if(!strcmp(pads[i].name, name))
|
||||||
|
{
|
||||||
|
sig=(void*)pads[i].signal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
*signal=sig;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void set_conio_terminal_mode(void)
|
||||||
|
{
|
||||||
|
struct termios new_termios;
|
||||||
|
|
||||||
|
tcgetattr(0, &new_termios);
|
||||||
|
cfmakeraw(&new_termios);
|
||||||
|
tcsetattr(0, TCSANOW, &new_termios);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int serial2console_start(void *b)
|
||||||
|
{
|
||||||
|
base =(struct event_base *)b;
|
||||||
|
printf("Loaded %p!\n", base);
|
||||||
|
// set_conio_terminal_mode();
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_handler(int fd, short event, void *arg)
|
||||||
|
{
|
||||||
|
struct session_s *s= (struct session_s*)arg;
|
||||||
|
char buffer[1024];
|
||||||
|
ssize_t read_len;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
read_len = read(fd, buffer, 1024);
|
||||||
|
for(i = 0; i < read_len; i++)
|
||||||
|
{
|
||||||
|
s->databuf[(s->data_start + s->datalen ) % 2048] = buffer[i];
|
||||||
|
s->datalen++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void event_handler(int fd, short event, void *arg)
|
||||||
|
{
|
||||||
|
//printf("hit\n");
|
||||||
|
if (event & EV_READ)
|
||||||
|
{
|
||||||
|
read_handler(fd, event, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int serial2console_new(void **sess, char *args)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct timeval tv = {1, 0};
|
||||||
|
struct session_s *s=NULL;
|
||||||
|
|
||||||
|
if(!sess)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
s=(struct session_s*)malloc(sizeof(struct session_s));
|
||||||
|
if(!s)
|
||||||
|
{
|
||||||
|
ret=RC_NOENMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(s, 0, sizeof(struct session_s));
|
||||||
|
s->ev = event_new(base, fileno(stdin), EV_READ | EV_PERSIST , event_handler, s);
|
||||||
|
event_add(s->ev, &tv);
|
||||||
|
|
||||||
|
out:
|
||||||
|
*sess=(void*)s;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial2console_add_pads(void *sess, struct pad_list_s *plist)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
struct pad_s *pads;
|
||||||
|
if(!sess || !plist)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pads = plist->pads;
|
||||||
|
if(!strcmp(plist->name, "serial"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sink_data", (void**)&s->rx);
|
||||||
|
lambdasim_module_pads_get(pads, "sink_valid", (void**)&s->rx_valid);
|
||||||
|
lambdasim_module_pads_get(pads, "sink_ready", (void**)&s->rx_ready);
|
||||||
|
lambdasim_module_pads_get(pads, "source_data", (void**)&s->tx);
|
||||||
|
lambdasim_module_pads_get(pads, "source_valid", (void**)&s->tx_valid);
|
||||||
|
lambdasim_module_pads_get(pads, "source_ready", (void**)&s->tx_ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(plist->name, "sys_clk"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
static int serial2console_tick(void *sess)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
if(*s->sys_clk == 0)
|
||||||
|
{
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
*s->tx_ready = 1;
|
||||||
|
if(*s->tx_valid)
|
||||||
|
{
|
||||||
|
if(*s->tx == '\n')
|
||||||
|
{
|
||||||
|
printf("\r");
|
||||||
|
}
|
||||||
|
printf("%c", *s->tx);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*s->rx_valid=0;
|
||||||
|
if(s->datalen)
|
||||||
|
{
|
||||||
|
|
||||||
|
*s->rx=s->databuf[s->data_start];
|
||||||
|
s->data_start = (s->data_start + 1) % 2048;
|
||||||
|
s->datalen--;
|
||||||
|
*s->rx_valid=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ext_module_s ext_mod = {
|
||||||
|
"serial2console",
|
||||||
|
serial2console_start,
|
||||||
|
serial2console_new,
|
||||||
|
serial2console_add_pads,
|
||||||
|
NULL,
|
||||||
|
serial2console_tick
|
||||||
|
};
|
||||||
|
|
||||||
|
int lambdasim_ext_module_init(int (*register_module)(struct ext_module_s *))
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
ret = register_module(&ext_mod);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
include ../variables.mak
|
||||||
|
|
||||||
|
all: $(OBJ_DIR)/serial2tcp.so
|
||||||
|
|
||||||
|
include ../rules.mak
|
|
@ -0,0 +1,300 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <event2/listener.h>
|
||||||
|
#include <event2/util.h>
|
||||||
|
#include <event2/event.h>
|
||||||
|
|
||||||
|
#include <json-c/json.h>
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
struct session_s {
|
||||||
|
char *tx;
|
||||||
|
char *tx_valid;
|
||||||
|
char *tx_ready;
|
||||||
|
char *rx;
|
||||||
|
char *rx_valid;
|
||||||
|
char *rx_ready;
|
||||||
|
char *sys_clk;
|
||||||
|
struct event *ev;
|
||||||
|
char databuf[2048];
|
||||||
|
int data_start;
|
||||||
|
int datalen;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct event_base *base;
|
||||||
|
|
||||||
|
|
||||||
|
int lambdasim_module_get_args( char *args, char *arg, char **val)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
json_object *jsobj=NULL;
|
||||||
|
json_object *obj=NULL;
|
||||||
|
char *value=NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
jsobj = json_tokener_parse(args);
|
||||||
|
if(NULL==jsobj)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error parsing json arg: %s \n", args);
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(!json_object_is_type(jsobj, json_type_object))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Arg must be type object! : %s \n", args);
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
obj=NULL;
|
||||||
|
r = json_object_object_get_ex(jsobj, arg, &obj);
|
||||||
|
if(!r)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not find object: \"%s\" (%s)\n", arg, args);
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
value=strdup(json_object_get_string(obj));
|
||||||
|
|
||||||
|
out:
|
||||||
|
*val = value;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int lambdasim_module_pads_get( struct pad_s *pads, char *name, void **signal)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *sig=NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!pads || !name || !signal)
|
||||||
|
{
|
||||||
|
ret=RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while(pads[i].name)
|
||||||
|
{
|
||||||
|
if(!strcmp(pads[i].name, name))
|
||||||
|
{
|
||||||
|
sig=(void*)pads[i].signal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
*signal=sig;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int serial2tcp_start(void *b)
|
||||||
|
{
|
||||||
|
base =(struct event_base *)b;
|
||||||
|
printf("Loaded %p!\n", base);
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_handler(int fd, short event, void *arg)
|
||||||
|
{
|
||||||
|
struct session_s *s= (struct session_s*)arg;
|
||||||
|
char buffer[1024];
|
||||||
|
ssize_t read_len;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
read_len = read(fd, buffer, 1024);
|
||||||
|
for(i = 0; i < read_len; i++)
|
||||||
|
{
|
||||||
|
s->databuf[(s->data_start + s->datalen ) % 2048] = buffer[i];
|
||||||
|
s->datalen++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void event_handler(int fd, short event, void *arg)
|
||||||
|
{
|
||||||
|
//printf("hit\n");
|
||||||
|
if (event & EV_READ)
|
||||||
|
{
|
||||||
|
read_handler(fd, event, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx)
|
||||||
|
{
|
||||||
|
struct session_s *s= (struct session_s*)ctx;
|
||||||
|
struct timeval tv = {1, 0};
|
||||||
|
|
||||||
|
s->fd = fd;
|
||||||
|
s->ev = event_new(base, fd, EV_READ | EV_PERSIST , event_handler, s);
|
||||||
|
event_add(s->ev, &tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
accept_error_cb(struct evconnlistener *listener, void *ctx)
|
||||||
|
{
|
||||||
|
struct event_base *base = evconnlistener_get_base(listener);
|
||||||
|
eprintf("ERRROR\n");
|
||||||
|
|
||||||
|
event_base_loopexit(base, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial2tcp_new(void **sess, char *args)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct session_s *s=NULL;
|
||||||
|
char *cport=NULL;
|
||||||
|
int port;
|
||||||
|
struct evconnlistener *listener;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
|
||||||
|
|
||||||
|
if(!sess)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ret = lambdasim_module_get_args(args, "port", &cport);
|
||||||
|
{
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Found port %s\n", cport);
|
||||||
|
sscanf(cport, "%d", &port);
|
||||||
|
free(cport);
|
||||||
|
if(!port)
|
||||||
|
{
|
||||||
|
ret=RC_ERROR;
|
||||||
|
fprintf(stderr, "Invalid port selected!\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s=(struct session_s*)malloc(sizeof(struct session_s));
|
||||||
|
if(!s)
|
||||||
|
{
|
||||||
|
ret=RC_NOENMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(s, 0, sizeof(struct session_s));
|
||||||
|
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = htonl(0);
|
||||||
|
sin.sin_port = htons(port);
|
||||||
|
listener = evconnlistener_new_bind(base, accept_conn_cb, s, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&sin, sizeof(sin));
|
||||||
|
if (!listener)
|
||||||
|
{
|
||||||
|
ret=RC_ERROR;
|
||||||
|
eprintf("Can't bind port %d\n!\n", port);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
evconnlistener_set_error_cb(listener, accept_error_cb);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
out:
|
||||||
|
*sess=(void*)s;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial2tcp_add_pads(void *sess, struct pad_list_s *plist)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
struct pad_s *pads;
|
||||||
|
if(!sess || !plist)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pads = plist->pads;
|
||||||
|
if(!strcmp(plist->name, "serial"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sink_data", (void**)&s->rx);
|
||||||
|
lambdasim_module_pads_get(pads, "sink_valid", (void**)&s->rx_valid);
|
||||||
|
lambdasim_module_pads_get(pads, "sink_ready", (void**)&s->rx_ready);
|
||||||
|
lambdasim_module_pads_get(pads, "source_data", (void**)&s->tx);
|
||||||
|
lambdasim_module_pads_get(pads, "source_valid", (void**)&s->tx_valid);
|
||||||
|
lambdasim_module_pads_get(pads, "source_ready", (void**)&s->tx_ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(plist->name, "sys_clk"))
|
||||||
|
{
|
||||||
|
lambdasim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
static int serial2tcp_tick(void *sess)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
int ret=RC_OK;
|
||||||
|
|
||||||
|
struct session_s *s=(struct session_s*)sess;
|
||||||
|
if(*s->sys_clk == 0)
|
||||||
|
{
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*s->tx_ready = 1;
|
||||||
|
if(s->fd && *s->tx_valid)
|
||||||
|
{
|
||||||
|
c = *s->tx;
|
||||||
|
if(-1 ==write(s->fd, &c, 1))
|
||||||
|
{
|
||||||
|
eprintf("Error writing on socket\n");
|
||||||
|
ret = RC_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*s->rx_valid=0;
|
||||||
|
if(s->datalen)
|
||||||
|
{
|
||||||
|
*s->rx=s->databuf[s->data_start];
|
||||||
|
s->data_start = (s->data_start + 1) % 2048;
|
||||||
|
s->datalen--;
|
||||||
|
*s->rx_valid=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ext_module_s ext_mod = {
|
||||||
|
"serial2tcp",
|
||||||
|
serial2tcp_start,
|
||||||
|
serial2tcp_new,
|
||||||
|
serial2tcp_add_pads,
|
||||||
|
NULL,
|
||||||
|
serial2tcp_tick
|
||||||
|
};
|
||||||
|
|
||||||
|
int lambdasim_ext_module_init(int (*register_module)(struct ext_module_s *))
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
ret = register_module(&ext_mod);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wall -O3 -ggdb -fPIC -Werror
|
||||||
|
LDFLAGS = -levent -shared -fPIC
|
||||||
|
|
||||||
|
OBJ_DIR ?= .
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "pads.h"
|
||||||
|
|
||||||
|
static struct pad_list_s *padlist=NULL;
|
||||||
|
int lambdasim_register_pads(struct pad_s *pads, char *interface_name, int index)
|
||||||
|
{
|
||||||
|
int ret = RC_OK;
|
||||||
|
|
||||||
|
struct pad_list_s *pl=NULL;
|
||||||
|
if(!pads || !interface_name)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid argument\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pl = (struct pad_list_s *)malloc(sizeof(struct pad_list_s));
|
||||||
|
if(NULL == pl)
|
||||||
|
{
|
||||||
|
ret = RC_NOENMEM;
|
||||||
|
eprintf("Not enough mem\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(pl, 0, sizeof(struct pad_list_s));
|
||||||
|
|
||||||
|
pl->index = index; /* Do we really need it ?*/
|
||||||
|
pl->name = strdup(interface_name);
|
||||||
|
pl->pads = pads;
|
||||||
|
|
||||||
|
pl->next = padlist;
|
||||||
|
padlist = pl;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lambdasim_pads_get_list(struct pad_list_s **plist)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
|
||||||
|
|
||||||
|
if(!plist)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid argument\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*plist = padlist;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lambdasim_pads_find(struct pad_list_s *first, char *name, int index, struct pad_list_s **found)
|
||||||
|
{
|
||||||
|
struct pad_list_s *list = NULL;
|
||||||
|
int ret=RC_OK;
|
||||||
|
if(!first || !name || !found)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid arg\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(list = first; list; list=list->next)
|
||||||
|
{
|
||||||
|
if(!strcmp(name, list->name) && (list->index == index))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
*found = list;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#ifndef __PADS_H_
|
||||||
|
#define __PADS_H_
|
||||||
|
|
||||||
|
struct pad_s {
|
||||||
|
char *name;
|
||||||
|
size_t len;
|
||||||
|
void *signal;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pad_list_s {
|
||||||
|
char *name;
|
||||||
|
struct pad_s *pads;
|
||||||
|
int index;
|
||||||
|
struct pad_list_s *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
int lambdasim_pads_get_list(struct pad_list_s **plist);
|
||||||
|
int lambdasim_pads_find(struct pad_list_s *first, char *name, int index, struct pad_list_s **found);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" int lambdasim_register_pads(struct pad_s *pads, char *interface_name, int index);
|
||||||
|
#else
|
||||||
|
int lambdasim_register_pads(struct pad_s *pads, char *interface_name, int index);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,339 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
static int file_to_js(char *filename, json_object **obj)
|
||||||
|
{
|
||||||
|
int ret = RC_OK;
|
||||||
|
struct json_tokener *tok=NULL;
|
||||||
|
json_object *pobj=NULL;
|
||||||
|
enum json_tokener_error jerr;
|
||||||
|
FILE *in=NULL;
|
||||||
|
int linenum=0;
|
||||||
|
char *lineptr=NULL;
|
||||||
|
size_t len, len2;
|
||||||
|
|
||||||
|
if(!filename || !obj)
|
||||||
|
{
|
||||||
|
ret=RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
in = fopen(filename, "r");
|
||||||
|
if(!in)
|
||||||
|
{
|
||||||
|
eprintf("Can't open configuration file: %s\n", filename);
|
||||||
|
ret= RC_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tok = json_tokener_new();
|
||||||
|
if(!tok)
|
||||||
|
{
|
||||||
|
ret=RC_ERROR;
|
||||||
|
eprintf("Can't create new tokener\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
linenum++;
|
||||||
|
len=32768;
|
||||||
|
len2 = getline(&lineptr, &len, in);
|
||||||
|
if(len2 == -1)
|
||||||
|
{
|
||||||
|
ret=RC_ERROR;
|
||||||
|
eprintf("End of file !\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pobj = json_tokener_parse_ex(tok, lineptr, len2);
|
||||||
|
if((jerr = json_tokener_get_error(tok)) == json_tokener_success)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((jerr = json_tokener_get_error(tok)) != json_tokener_continue)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR in %s:\n", filename);
|
||||||
|
fprintf(stderr, "line:%d:\n%s",linenum, lineptr);
|
||||||
|
jerr = json_tokener_get_error(tok);
|
||||||
|
fprintf(stderr, "json parse error: %s\n", json_tokener_error_desc(jerr));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
free(lineptr);
|
||||||
|
lineptr=NULL;
|
||||||
|
}while(1);
|
||||||
|
|
||||||
|
*obj=pobj;
|
||||||
|
pobj=NULL;
|
||||||
|
out:
|
||||||
|
|
||||||
|
if(pobj)
|
||||||
|
{
|
||||||
|
json_object_put(pobj);
|
||||||
|
}
|
||||||
|
if(tok)
|
||||||
|
{
|
||||||
|
json_tokener_free(tok);
|
||||||
|
}
|
||||||
|
if(lineptr)
|
||||||
|
{
|
||||||
|
free(lineptr);
|
||||||
|
}
|
||||||
|
if(in)
|
||||||
|
{
|
||||||
|
fclose(in);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_to_interface_list(json_object *interface, struct interface_s **iface)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
int n, i;
|
||||||
|
json_object *obj;
|
||||||
|
json_object *name;
|
||||||
|
json_object *index;
|
||||||
|
|
||||||
|
struct interface_s *t_iface=NULL;
|
||||||
|
|
||||||
|
if(!interface || !iface)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid argument\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!json_object_is_type(interface, json_type_array))
|
||||||
|
{
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
eprintf("Interface must be an array\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = json_object_array_length(interface);
|
||||||
|
t_iface = (struct interface_s *)malloc(sizeof(struct interface_s) * (n + 1));
|
||||||
|
if(!t_iface)
|
||||||
|
{
|
||||||
|
ret= RC_NOENMEM;
|
||||||
|
eprintf("Not enough memory\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(t_iface, 0,sizeof(struct interface_s) * (n + 1));
|
||||||
|
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
obj = json_object_array_get_idx(interface, i);
|
||||||
|
if(json_object_is_type(obj, json_type_object))
|
||||||
|
{
|
||||||
|
if(!json_object_object_get_ex(obj, "name", &name))
|
||||||
|
{
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
eprintf("Module interface must have a name (%s)!\n", json_object_to_json_string(obj));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
t_iface[i].name = strdup(json_object_get_string(name));
|
||||||
|
|
||||||
|
if(json_object_object_get_ex(obj, "index", &index))
|
||||||
|
{
|
||||||
|
if(!json_object_is_type(index, json_type_int))
|
||||||
|
{
|
||||||
|
ret = RC_JSERROR;
|
||||||
|
eprintf("Interface Index must be an int ! (%s)\n", json_object_to_json_string(obj));
|
||||||
|
}
|
||||||
|
t_iface[i].index = json_object_get_int(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(json_object_is_type(obj, json_type_string))
|
||||||
|
{
|
||||||
|
t_iface[i].name = strdup(json_object_get_string(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*iface = t_iface;
|
||||||
|
t_iface = NULL;
|
||||||
|
out:
|
||||||
|
if(t_iface)
|
||||||
|
{
|
||||||
|
free(t_iface);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int module_list_free(struct module_s *mod)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
struct module_s *mnext;
|
||||||
|
int i;
|
||||||
|
while(mod)
|
||||||
|
{
|
||||||
|
mnext = mod->next;
|
||||||
|
if(mod->iface)
|
||||||
|
{
|
||||||
|
for(i = 0; i < mod->niface; i++)
|
||||||
|
{
|
||||||
|
if(mod->iface[i].name)
|
||||||
|
{
|
||||||
|
free(mod->iface[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(mod->iface);
|
||||||
|
if(mod->name)
|
||||||
|
{
|
||||||
|
free(mod->name);
|
||||||
|
}
|
||||||
|
if(mod->args)
|
||||||
|
{
|
||||||
|
free(mod->args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(mod);
|
||||||
|
mod = mnext;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_to_module_list(json_object *obj, struct module_s **mod)
|
||||||
|
{
|
||||||
|
struct module_s *m=NULL;
|
||||||
|
struct module_s *first=NULL;
|
||||||
|
|
||||||
|
json_object *tobj;
|
||||||
|
int ret=RC_OK;
|
||||||
|
int i, n, len;
|
||||||
|
json_object *name;
|
||||||
|
json_object *args;
|
||||||
|
json_object *interface;
|
||||||
|
json_object *tickfirst;
|
||||||
|
|
||||||
|
if(!obj || !mod)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Wrong arguments\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!json_object_is_type(obj, json_type_array))
|
||||||
|
{
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
eprintf("Config file must be an array\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = json_object_array_length(obj);
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
tobj = json_object_array_get_idx(obj, i);
|
||||||
|
if(!json_object_object_get_ex(tobj, "module", &name))
|
||||||
|
{
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
eprintf("expected \"module\" in object (%s)\n", json_object_to_json_string(tobj));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!json_object_object_get_ex(tobj, "interface", &interface))
|
||||||
|
{
|
||||||
|
ret=RC_JSERROR;
|
||||||
|
eprintf("expected \"interface\" in object (%s)\n", json_object_to_json_string(tobj));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
args = NULL;
|
||||||
|
json_object_object_get_ex(tobj, "args", &args);
|
||||||
|
|
||||||
|
tickfirst=NULL;
|
||||||
|
json_object_object_get_ex(tobj, "tickfirst", &tickfirst);
|
||||||
|
|
||||||
|
|
||||||
|
if(m)
|
||||||
|
{
|
||||||
|
m->next=(struct module_s *)malloc(sizeof(struct module_s));
|
||||||
|
m=m->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m=(struct module_s *)malloc(sizeof(struct module_s));
|
||||||
|
}
|
||||||
|
if(!m)
|
||||||
|
{
|
||||||
|
ret = RC_NOENMEM;
|
||||||
|
eprintf("Not enough memory\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(!first)
|
||||||
|
{
|
||||||
|
first = m;
|
||||||
|
}
|
||||||
|
memset(m, 0, sizeof(struct module_s));
|
||||||
|
ret = json_to_interface_list(interface, &m->iface);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
|
||||||
|
while(m->iface[len++].name);
|
||||||
|
m->niface= len-1;
|
||||||
|
m->name = strdup(json_object_get_string(name));
|
||||||
|
if(args)
|
||||||
|
{
|
||||||
|
m->args = strdup(json_object_to_json_string(args));
|
||||||
|
}
|
||||||
|
if(tickfirst)
|
||||||
|
{
|
||||||
|
m->tickfirst = json_object_get_boolean(tickfirst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*mod = first;
|
||||||
|
first=NULL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if(first)
|
||||||
|
{
|
||||||
|
module_list_free(first);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lambdasim_file_to_module_list(char *filename, struct module_s **mod)
|
||||||
|
{
|
||||||
|
struct module_s *m=NULL;
|
||||||
|
json_object *obj=NULL;
|
||||||
|
int ret=RC_OK;
|
||||||
|
|
||||||
|
if(!filename || !mod)
|
||||||
|
{
|
||||||
|
ret = RC_INVARG;
|
||||||
|
eprintf("Invalid argument\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = file_to_js(filename, &obj);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = json_to_module_list(obj, &m);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mod = m;
|
||||||
|
m = NULL;
|
||||||
|
out:
|
||||||
|
if(m)
|
||||||
|
{
|
||||||
|
module_list_free(m);
|
||||||
|
}
|
||||||
|
if(obj)
|
||||||
|
{
|
||||||
|
json_object_put(obj);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,244 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <netinet/in.h>
|
||||||
|
# ifdef _XOPEN_SOURCE_EXTENDED
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# endif
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "modules.h"
|
||||||
|
#include "pads.h"
|
||||||
|
#include "veril.h"
|
||||||
|
|
||||||
|
#include <event2/listener.h>
|
||||||
|
#include <event2/util.h>
|
||||||
|
#include <event2/event.h>
|
||||||
|
|
||||||
|
void lambdasim_init(void **out);
|
||||||
|
|
||||||
|
|
||||||
|
struct session_list_s {
|
||||||
|
void *session;
|
||||||
|
char tickfirst;
|
||||||
|
struct ext_module_s *module;
|
||||||
|
struct session_list_s *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct session_list_s *sesslist=NULL;
|
||||||
|
|
||||||
|
static int lambdasim_initialize_all(void **dut, void *base)
|
||||||
|
{
|
||||||
|
struct module_s *ml=NULL;
|
||||||
|
struct module_s *mli=NULL;
|
||||||
|
struct ext_module_list_s *mlist=NULL;
|
||||||
|
struct ext_module_list_s *pmlist=NULL;
|
||||||
|
//struct ext_module_list_s *mlisti=NULL;
|
||||||
|
struct pad_list_s *plist=NULL;
|
||||||
|
struct pad_list_s *pplist=NULL;
|
||||||
|
struct session_list_s *slist=NULL;
|
||||||
|
void *vdut=NULL;
|
||||||
|
int i;
|
||||||
|
int ret = RC_OK;
|
||||||
|
|
||||||
|
/* Load external modules */
|
||||||
|
ret = lambdasim_load_ext_modules(&mlist);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for(pmlist = mlist; pmlist; pmlist=pmlist->next)
|
||||||
|
{
|
||||||
|
if(pmlist->module->start)
|
||||||
|
{
|
||||||
|
pmlist->module->start(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Load configuration */
|
||||||
|
ret = lambdasim_file_to_module_list("sim_config.js", &ml);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Init generated */
|
||||||
|
lambdasim_init(&vdut);
|
||||||
|
|
||||||
|
/* Get pads from generated */
|
||||||
|
ret = lambdasim_pads_get_list(&plist);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(mli = ml; mli; mli=mli->next)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Find the module in the external module */
|
||||||
|
pmlist = NULL;
|
||||||
|
ret = lambdasim_find_ext_module(mlist, mli->name, &pmlist );
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(NULL == pmlist)
|
||||||
|
{
|
||||||
|
eprintf("Could not find module %s\n", mli->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
slist=(struct session_list_s *)malloc(sizeof(struct session_list_s));
|
||||||
|
if(NULL == slist)
|
||||||
|
{
|
||||||
|
ret = RC_NOENMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(slist, 0, sizeof(struct session_list_s));
|
||||||
|
|
||||||
|
slist->tickfirst = mli->tickfirst;
|
||||||
|
slist->module = pmlist->module;
|
||||||
|
slist->next = sesslist;
|
||||||
|
ret = pmlist->module->new_sess(&slist->session, mli->args);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
sesslist = slist;
|
||||||
|
|
||||||
|
/* For each interface */
|
||||||
|
for(i = 0; i < mli->niface; i++)
|
||||||
|
{
|
||||||
|
/*Find the pads */
|
||||||
|
pplist=NULL;
|
||||||
|
ret = lambdasim_pads_find(plist, mli->iface[i].name, mli->iface[i].index, &pplist);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(NULL == pplist)
|
||||||
|
{
|
||||||
|
eprintf("Could not find interface %s with index %d\n", mli->iface[i].name, mli->iface[i].index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = pmlist->module->add_pads(slist->session, pplist);
|
||||||
|
if(RC_OK != ret)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dut = vdut;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int lambdasim_sort_session()
|
||||||
|
{
|
||||||
|
struct session_list_s *s;
|
||||||
|
struct session_list_s *sprev=sesslist;
|
||||||
|
|
||||||
|
if(!sesslist->next)
|
||||||
|
{
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(s = sesslist->next; s; s=s->next)
|
||||||
|
{
|
||||||
|
if(s->tickfirst)
|
||||||
|
{
|
||||||
|
sprev->next = s->next;
|
||||||
|
s->next = sesslist;
|
||||||
|
sesslist=s;
|
||||||
|
s=sprev;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sprev = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RC_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
struct event *ev;
|
||||||
|
static void cb(int sock, short which, void *arg)
|
||||||
|
{
|
||||||
|
struct session_list_s *s;
|
||||||
|
void *vdut=arg;
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
//lambdasim_eval(vdut);
|
||||||
|
for(i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
for(s = sesslist; s; s=s->next)
|
||||||
|
{
|
||||||
|
if(s->tickfirst)
|
||||||
|
s->module->tick(s->session);
|
||||||
|
}
|
||||||
|
lambdasim_eval(vdut);
|
||||||
|
for(s = sesslist; s; s=s->next)
|
||||||
|
{
|
||||||
|
if(!s->tickfirst)
|
||||||
|
s->module->tick(s->session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//lambdasim_eval(vdut);
|
||||||
|
|
||||||
|
|
||||||
|
if (!evtimer_pending(ev, NULL)) {
|
||||||
|
event_del(ev);
|
||||||
|
evtimer_add(ev, &tv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
void *vdut=NULL;
|
||||||
|
struct event_base *base=NULL;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA wsa_data;
|
||||||
|
WSAStartup(0x0201, &wsa_data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
base = event_base_new();
|
||||||
|
if(!base)
|
||||||
|
{
|
||||||
|
eprintf("Can't allocate base\n");
|
||||||
|
ret=RC_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RC_OK != (ret = lambdasim_initialize_all(&vdut, base)))
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RC_OK != (ret = lambdasim_sort_session()))
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
ev = event_new(base, -1, EV_PERSIST, cb, vdut);
|
||||||
|
event_add(ev, &tv);
|
||||||
|
|
||||||
|
event_base_dispatch(base);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,804 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2013-2016, tinydir authors:
|
||||||
|
- Cong Xu
|
||||||
|
- Lautis Sun
|
||||||
|
- Baudouin Feildel
|
||||||
|
- Andargor <andargor@yahoo.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef TINYDIR_H
|
||||||
|
#define TINYDIR_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ((defined _UNICODE) && !(defined UNICODE))
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ((defined UNICODE) && !(defined _UNICODE))
|
||||||
|
#define _UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# include <tchar.h>
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning (disable : 4996)
|
||||||
|
#else
|
||||||
|
# include <dirent.h>
|
||||||
|
# include <libgen.h>
|
||||||
|
# include <sys/stat.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
# include <tchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* types */
|
||||||
|
|
||||||
|
/* Windows UNICODE wide character support */
|
||||||
|
#if defined _MSC_VER || defined __MINGW32__
|
||||||
|
#define _tinydir_char_t TCHAR
|
||||||
|
#define TINYDIR_STRING(s) _TEXT(s)
|
||||||
|
#define _tinydir_strlen _tcslen
|
||||||
|
#define _tinydir_strcpy _tcscpy
|
||||||
|
#define _tinydir_strcat _tcscat
|
||||||
|
#define _tinydir_strcmp _tcscmp
|
||||||
|
#define _tinydir_strrchr _tcsrchr
|
||||||
|
#define _tinydir_strncmp _tcsncmp
|
||||||
|
#else
|
||||||
|
#define _tinydir_char_t char
|
||||||
|
#define TINYDIR_STRING(s) s
|
||||||
|
#define _tinydir_strlen strlen
|
||||||
|
#define _tinydir_strcpy strcpy
|
||||||
|
#define _tinydir_strcat strcat
|
||||||
|
#define _tinydir_strcmp strcmp
|
||||||
|
#define _tinydir_strrchr strrchr
|
||||||
|
#define _tinydir_strncmp strncmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
#include <windows.h>
|
||||||
|
#define _TINYDIR_PATH_MAX MAX_PATH
|
||||||
|
#elif defined __linux__
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#define _TINYDIR_PATH_MAX PATH_MAX
|
||||||
|
#else
|
||||||
|
#define _TINYDIR_PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
/* extra chars for the "\\*" mask */
|
||||||
|
# define _TINYDIR_PATH_EXTRA 2
|
||||||
|
#else
|
||||||
|
# define _TINYDIR_PATH_EXTRA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _TINYDIR_FILENAME_MAX 256
|
||||||
|
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
#define _TINYDIR_DRIVE_MAX 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define _TINYDIR_FUNC static __inline
|
||||||
|
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||||
|
# define _TINYDIR_FUNC static __inline__
|
||||||
|
#else
|
||||||
|
# define _TINYDIR_FUNC static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||||
|
#ifdef TINYDIR_USE_READDIR_R
|
||||||
|
|
||||||
|
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||||
|
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||||
|
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
||||||
|
_POSIX_SOURCE
|
||||||
|
# define _TINYDIR_HAS_READDIR_R
|
||||||
|
#endif
|
||||||
|
#if _POSIX_C_SOURCE >= 200112L
|
||||||
|
# define _TINYDIR_HAS_FPATHCONF
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||||
|
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||||
|
# define _TINYDIR_HAS_DIRFD
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
||||||
|
defined _PC_NAME_MAX
|
||||||
|
# define _TINYDIR_USE_FPATHCONF
|
||||||
|
#endif
|
||||||
|
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
||||||
|
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||||
|
# define _TINYDIR_USE_READDIR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Use readdir by default */
|
||||||
|
#else
|
||||||
|
# define _TINYDIR_USE_READDIR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||||
|
#define _TINYDIR_DIR _WDIR
|
||||||
|
#define _tinydir_dirent _wdirent
|
||||||
|
#define _tinydir_opendir _wopendir
|
||||||
|
#define _tinydir_readdir _wreaddir
|
||||||
|
#define _tinydir_closedir _wclosedir
|
||||||
|
#else
|
||||||
|
#define _TINYDIR_DIR DIR
|
||||||
|
#define _tinydir_dirent dirent
|
||||||
|
#define _tinydir_opendir opendir
|
||||||
|
#define _tinydir_readdir readdir
|
||||||
|
#define _tinydir_closedir closedir
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||||
|
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||||
|
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||||
|
#else
|
||||||
|
#error "Either define both alloc and free or none of them!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_TINYDIR_MALLOC)
|
||||||
|
#define _TINYDIR_MALLOC(_size) malloc(_size)
|
||||||
|
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||||
|
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||||
|
|
||||||
|
typedef struct tinydir_file
|
||||||
|
{
|
||||||
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
|
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||||
|
_tinydir_char_t *extension;
|
||||||
|
int is_dir;
|
||||||
|
int is_reg;
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
struct _stat _s;
|
||||||
|
#else
|
||||||
|
struct stat _s;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} tinydir_file;
|
||||||
|
|
||||||
|
typedef struct tinydir_dir
|
||||||
|
{
|
||||||
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
|
int has_next;
|
||||||
|
size_t n_files;
|
||||||
|
|
||||||
|
tinydir_file *_files;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
HANDLE _h;
|
||||||
|
WIN32_FIND_DATA _f;
|
||||||
|
#else
|
||||||
|
_TINYDIR_DIR *_d;
|
||||||
|
struct _tinydir_dirent *_e;
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
struct _tinydir_dirent *_ep;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} tinydir_dir;
|
||||||
|
|
||||||
|
|
||||||
|
/* declarations */
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void tinydir_close(tinydir_dir *dir);
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_next(tinydir_dir *dir);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void _tinydir_get_ext(tinydir_file *file);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int _tinydir_file_cmp(const void *a, const void *b);
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* definitions*/
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||||
|
{
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
int error;
|
||||||
|
int size; /* using int size */
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||||
|
#endif
|
||||||
|
_tinydir_char_t *pathp;
|
||||||
|
|
||||||
|
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialise dir */
|
||||||
|
dir->_files = NULL;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
dir->_h = INVALID_HANDLE_VALUE;
|
||||||
|
#else
|
||||||
|
dir->_d = NULL;
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
dir->_ep = NULL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
tinydir_close(dir);
|
||||||
|
|
||||||
|
_tinydir_strcpy(dir->path, path);
|
||||||
|
/* Remove trailing slashes */
|
||||||
|
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||||
|
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
||||||
|
{
|
||||||
|
*pathp = TINYDIR_STRING('\0');
|
||||||
|
pathp++;
|
||||||
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
_tinydir_strcpy(path_buf, dir->path);
|
||||||
|
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||||
|
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||||
|
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
#else
|
||||||
|
dir->_d = _tinydir_opendir(path);
|
||||||
|
if (dir->_d == NULL)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read first file */
|
||||||
|
dir->has_next = 1;
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifdef _TINYDIR_USE_READDIR
|
||||||
|
dir->_e = _tinydir_readdir(dir->_d);
|
||||||
|
#else
|
||||||
|
/* allocate dirent buffer for readdir_r */
|
||||||
|
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||||
|
if (size == -1) return -1;
|
||||||
|
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||||
|
if (dir->_ep == NULL) return -1;
|
||||||
|
|
||||||
|
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||||
|
if (error != 0) return -1;
|
||||||
|
#endif
|
||||||
|
if (dir->_e == NULL)
|
||||||
|
{
|
||||||
|
dir->has_next = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tinydir_close(dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||||
|
{
|
||||||
|
/* Count the number of files first, to pre-allocate the files array */
|
||||||
|
size_t n_files = 0;
|
||||||
|
if (tinydir_open(dir, path) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while (dir->has_next)
|
||||||
|
{
|
||||||
|
n_files++;
|
||||||
|
if (tinydir_next(dir) == -1)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tinydir_close(dir);
|
||||||
|
|
||||||
|
if (tinydir_open(dir, path) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir->n_files = 0;
|
||||||
|
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||||
|
if (dir->_files == NULL)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
while (dir->has_next)
|
||||||
|
{
|
||||||
|
tinydir_file *p_file;
|
||||||
|
dir->n_files++;
|
||||||
|
|
||||||
|
p_file = &dir->_files[dir->n_files - 1];
|
||||||
|
if (tinydir_readfile(dir, p_file) == -1)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tinydir_next(dir) == -1)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just in case the number of files has changed between the first and
|
||||||
|
second reads, terminate without writing into unallocated memory */
|
||||||
|
if (dir->n_files == n_files)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tinydir_close(dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void tinydir_close(tinydir_dir *dir)
|
||||||
|
{
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(dir->path, 0, sizeof(dir->path));
|
||||||
|
dir->has_next = 0;
|
||||||
|
dir->n_files = 0;
|
||||||
|
_TINYDIR_FREE(dir->_files);
|
||||||
|
dir->_files = NULL;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (dir->_h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
FindClose(dir->_h);
|
||||||
|
}
|
||||||
|
dir->_h = INVALID_HANDLE_VALUE;
|
||||||
|
#else
|
||||||
|
if (dir->_d)
|
||||||
|
{
|
||||||
|
_tinydir_closedir(dir->_d);
|
||||||
|
}
|
||||||
|
dir->_d = NULL;
|
||||||
|
dir->_e = NULL;
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
_TINYDIR_FREE(dir->_ep);
|
||||||
|
dir->_ep = NULL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_next(tinydir_dir *dir)
|
||||||
|
{
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!dir->has_next)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (FindNextFile(dir->_h, &dir->_f) == 0)
|
||||||
|
#else
|
||||||
|
#ifdef _TINYDIR_USE_READDIR
|
||||||
|
dir->_e = _tinydir_readdir(dir->_d);
|
||||||
|
#else
|
||||||
|
if (dir->_ep == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (dir->_e == NULL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
dir->has_next = 0;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (GetLastError() != ERROR_SUCCESS &&
|
||||||
|
GetLastError() != ERROR_NO_MORE_FILES)
|
||||||
|
{
|
||||||
|
tinydir_close(dir);
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
||||||
|
{
|
||||||
|
if (dir == NULL || file == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||||
|
#else
|
||||||
|
if (dir->_e == NULL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(dir->path) +
|
||||||
|
_tinydir_strlen(
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
dir->_f.cFileName
|
||||||
|
#else
|
||||||
|
dir->_e->d_name
|
||||||
|
#endif
|
||||||
|
) + 1 + _TINYDIR_PATH_EXTRA >=
|
||||||
|
_TINYDIR_PATH_MAX)
|
||||||
|
{
|
||||||
|
/* the path for the file will be too long */
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
dir->_f.cFileName
|
||||||
|
#else
|
||||||
|
dir->_e->d_name
|
||||||
|
#endif
|
||||||
|
) >= _TINYDIR_FILENAME_MAX)
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tinydir_strcpy(file->path, dir->path);
|
||||||
|
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
|
||||||
|
_tinydir_strcpy(file->name,
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
dir->_f.cFileName
|
||||||
|
#else
|
||||||
|
dir->_e->d_name
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
_tinydir_strcat(file->path, file->name);
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
if (_tstat(
|
||||||
|
#else
|
||||||
|
if (stat(
|
||||||
|
#endif
|
||||||
|
file->path, &file->_s) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_tinydir_get_ext(file);
|
||||||
|
|
||||||
|
file->is_dir =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
#else
|
||||||
|
S_ISDIR(file->_s.st_mode);
|
||||||
|
#endif
|
||||||
|
file->is_reg =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
||||||
|
(
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||||
|
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||||
|
#endif
|
||||||
|
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||||
|
#endif
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||||
|
#else
|
||||||
|
S_ISREG(file->_s.st_mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
||||||
|
{
|
||||||
|
if (dir == NULL || file == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (i >= dir->n_files)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
|
||||||
|
_tinydir_get_ext(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
||||||
|
{
|
||||||
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tinydir_strcpy(path, dir->_files[i].path);
|
||||||
|
tinydir_close(dir);
|
||||||
|
if (tinydir_open_sorted(dir, path) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open a single file given its path */
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
||||||
|
{
|
||||||
|
tinydir_dir dir;
|
||||||
|
int result = 0;
|
||||||
|
int found = 0;
|
||||||
|
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||||
|
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||||
|
_tinydir_char_t *dir_name;
|
||||||
|
_tinydir_char_t *base_name;
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
_tinydir_char_t drive_buf[_TINYDIR_DRIVE_MAX];
|
||||||
|
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the parent path */
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||||
|
_tsplitpath_s(
|
||||||
|
path,
|
||||||
|
drive_buf, _TINYDIR_DRIVE_MAX,
|
||||||
|
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
||||||
|
file_name_buf, _TINYDIR_FILENAME_MAX,
|
||||||
|
ext_buf, _TINYDIR_FILENAME_MAX);
|
||||||
|
#else
|
||||||
|
_tsplitpath(
|
||||||
|
path,
|
||||||
|
drive_buf,
|
||||||
|
dir_name_buf,
|
||||||
|
file_name_buf,
|
||||||
|
ext_buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* _splitpath_s not work fine with only filename and widechar support */
|
||||||
|
#ifdef _UNICODE
|
||||||
|
if (drive_buf[0] == L'\xFEFE')
|
||||||
|
drive_buf[0] = '\0';
|
||||||
|
if (dir_name_buf[0] == L'\xFEFE')
|
||||||
|
dir_name_buf[0] = '\0';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (errno)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||||
|
empty */
|
||||||
|
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
||||||
|
{
|
||||||
|
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||||
|
}
|
||||||
|
/* Concatenate the drive letter and dir name to form full dir name */
|
||||||
|
_tinydir_strcat(drive_buf, dir_name_buf);
|
||||||
|
dir_name = drive_buf;
|
||||||
|
/* Concatenate the file name and extension to form base name */
|
||||||
|
_tinydir_strcat(file_name_buf, ext_buf);
|
||||||
|
base_name = file_name_buf;
|
||||||
|
#else
|
||||||
|
_tinydir_strcpy(dir_name_buf, path);
|
||||||
|
dir_name = dirname(dir_name_buf);
|
||||||
|
_tinydir_strcpy(file_name_buf, path);
|
||||||
|
base_name =basename(file_name_buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Open the parent directory */
|
||||||
|
if (tinydir_open(&dir, dir_name) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read through the parent directory and look for the file */
|
||||||
|
while (dir.has_next)
|
||||||
|
{
|
||||||
|
if (tinydir_readfile(&dir, file) == -1)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
if (_tinydir_strcmp(file->name, base_name) == 0)
|
||||||
|
{
|
||||||
|
/* File found */
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tinydir_next(&dir);
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
errno = ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tinydir_close(&dir);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void _tinydir_get_ext(tinydir_file *file)
|
||||||
|
{
|
||||||
|
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||||
|
if (period == NULL)
|
||||||
|
{
|
||||||
|
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file->extension = period + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int _tinydir_file_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const tinydir_file *fa = (const tinydir_file *)a;
|
||||||
|
const tinydir_file *fb = (const tinydir_file *)b;
|
||||||
|
if (fa->is_dir != fb->is_dir)
|
||||||
|
{
|
||||||
|
return -(fa->is_dir - fb->is_dir);
|
||||||
|
}
|
||||||
|
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
/*
|
||||||
|
The following authored by Ben Hutchings <ben@decadent.org.uk>
|
||||||
|
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||||
|
*/
|
||||||
|
/* Calculate the required buffer size (in bytes) for directory *
|
||||||
|
* entries read from the given directory handle. Return -1 if this *
|
||||||
|
* this cannot be done. *
|
||||||
|
* *
|
||||||
|
* This code does not trust values of NAME_MAX that are less than *
|
||||||
|
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||||
|
* define it to be a smaller value. */
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
||||||
|
{
|
||||||
|
long name_max;
|
||||||
|
size_t name_end;
|
||||||
|
/* parameter may be unused */
|
||||||
|
(void)dirp;
|
||||||
|
|
||||||
|
#if defined _TINYDIR_USE_FPATHCONF
|
||||||
|
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||||
|
if (name_max == -1)
|
||||||
|
#if defined(NAME_MAX)
|
||||||
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||||
|
#else
|
||||||
|
return (size_t)(-1);
|
||||||
|
#endif
|
||||||
|
#elif defined(NAME_MAX)
|
||||||
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||||
|
#else
|
||||||
|
#error "buffer size for readdir_r cannot be determined"
|
||||||
|
#endif
|
||||||
|
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||||
|
return (name_end > sizeof(struct _tinydir_dirent) ?
|
||||||
|
name_end : sizeof(struct _tinydir_dirent));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
# if defined (_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "Vdut.h"
|
||||||
|
#include "Vdut.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "verilated_vcd_c.h"
|
||||||
|
#include <verilated.h>
|
||||||
|
|
||||||
|
|
||||||
|
VerilatedVcdC* tfp;
|
||||||
|
|
||||||
|
extern "C" void lambdasim_eval(void *vdut)
|
||||||
|
{
|
||||||
|
Vdut *dut = (Vdut*)vdut;
|
||||||
|
dut->eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void lambdasim_init_tracer(void *vdut)
|
||||||
|
{
|
||||||
|
Vdut *dut = (Vdut*)vdut;
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
tfp = new VerilatedVcdC;
|
||||||
|
dut->trace(tfp, 99);
|
||||||
|
tfp->open("dut.vcd");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void lambdasim_tracer_dump()
|
||||||
|
{
|
||||||
|
static unsigned int ticks=0;
|
||||||
|
tfp->dump(ticks++);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vluint64_t main_time = 0;
|
||||||
|
double sc_time_stamp()
|
||||||
|
{
|
||||||
|
return main_time;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* Copyright (C) 2017 LambdaConcept */
|
||||||
|
|
||||||
|
#ifndef __VERIL_H_
|
||||||
|
#define __VERIL_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" void lambdasim_eval(void *vdut);
|
||||||
|
extern "C" void lambdasim_init_tracer(void *vdut);
|
||||||
|
extern "C" void lambdasim_tracer_dump();
|
||||||
|
#else
|
||||||
|
void lambdasim_eval(void *vdut);
|
||||||
|
void lambdasim_init_tracer(void *vdut);
|
||||||
|
void lambdasim_tracer_dump();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,492 +0,0 @@
|
||||||
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
||||||
// License: BSD
|
|
||||||
#include "Vdut.h"
|
|
||||||
#include "verilated.h"
|
|
||||||
#include "verilated_vcd_c.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
|
|
||||||
#include <linux/if.h>
|
|
||||||
#include <linux/if_tun.h>
|
|
||||||
|
|
||||||
#include <SDL/SDL.h>
|
|
||||||
|
|
||||||
/* ios */
|
|
||||||
|
|
||||||
#ifdef SERIAL_SOURCE_VALID
|
|
||||||
#define WITH_SERIAL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ETH_SOURCE_VALID
|
|
||||||
#define WITH_ETH
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VGA_DE
|
|
||||||
#define WITH_VGA
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
|
||||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
|
||||||
|
|
||||||
int trace = 0;
|
|
||||||
|
|
||||||
vluint64_t main_time = 0;
|
|
||||||
double sc_time_stamp()
|
|
||||||
{
|
|
||||||
return main_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vdut* dut;
|
|
||||||
VerilatedVcdC* tfp;
|
|
||||||
|
|
||||||
/* Sim struct */
|
|
||||||
struct sim {
|
|
||||||
bool run;
|
|
||||||
|
|
||||||
unsigned int tick;
|
|
||||||
clock_t start;
|
|
||||||
clock_t end;
|
|
||||||
float speed;
|
|
||||||
|
|
||||||
#ifdef WITH_SERIAL_PTY
|
|
||||||
char serial_dev[64];
|
|
||||||
int serial_fd;
|
|
||||||
unsigned char serial_rx_data;
|
|
||||||
unsigned char serial_tx_data;
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_ETH
|
|
||||||
const char *eth_dev;
|
|
||||||
const char *eth_tap;
|
|
||||||
int eth_fd;
|
|
||||||
unsigned char eth_txbuffer[2048];
|
|
||||||
unsigned char eth_rxbuffer[2048];
|
|
||||||
int eth_txbuffer_len;
|
|
||||||
int eth_rxbuffer_len;
|
|
||||||
int eth_rxbuffer_pos;
|
|
||||||
int eth_last_source_valid;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Serial functions */
|
|
||||||
#ifndef WITH_SERIAL_PTY
|
|
||||||
struct termios orig_termios;
|
|
||||||
|
|
||||||
void reset_terminal_mode(void)
|
|
||||||
{
|
|
||||||
tcsetattr(0, TCSANOW, &orig_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_conio_terminal_mode(void)
|
|
||||||
{
|
|
||||||
struct termios new_termios;
|
|
||||||
|
|
||||||
/* take two copies - one for now, one for later */
|
|
||||||
tcgetattr(0, &orig_termios);
|
|
||||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
|
||||||
|
|
||||||
/* register cleanup handler, and set the new terminal mode */
|
|
||||||
atexit(reset_terminal_mode);
|
|
||||||
cfmakeraw(&new_termios);
|
|
||||||
tcsetattr(0, TCSANOW, &new_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kbhit(void)
|
|
||||||
{
|
|
||||||
struct timeval tv = { 0L, 0L };
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(0, &fds);
|
|
||||||
return select(1, &fds, NULL, NULL, &tv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getch(void)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
unsigned char c;
|
|
||||||
if((r = read(0, &c, sizeof(c))) < 0) {
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Ethernet functions */
|
|
||||||
/* create tap:
|
|
||||||
openvpn --mktun --dev tap0
|
|
||||||
ifconfig tap0 192.168.0.14 up
|
|
||||||
mknod /dev/net/tap0 c 10 200
|
|
||||||
delete tap:
|
|
||||||
openvpn --rmtun --dev tap0 */
|
|
||||||
#ifdef WITH_ETH
|
|
||||||
void eth_init(struct sim *s, const char *dev, const char*tap)
|
|
||||||
{
|
|
||||||
s->eth_txbuffer_len = 0;
|
|
||||||
s->eth_rxbuffer_len = 0;
|
|
||||||
s->eth_rxbuffer_pos = 0;
|
|
||||||
s->eth_last_source_valid = 0;
|
|
||||||
s->eth_dev = dev;
|
|
||||||
s->eth_tap = tap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void eth_open(struct sim *s)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct ifreq ifr;
|
|
||||||
s->eth_fd = open (s->eth_dev, O_RDWR);
|
|
||||||
if(s->eth_fd < 0) {
|
|
||||||
fprintf(stderr, " Could not open dev %s\n", s->eth_dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
|
||||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
|
||||||
strncpy(ifr.ifr_name, s->eth_tap, IFNAMSIZ);
|
|
||||||
|
|
||||||
if(ioctl(s->eth_fd, TUNSETIFF, (void *) &ifr) < 0) {
|
|
||||||
fprintf(stderr, " Could not set %s\n", s->eth_tap);
|
|
||||||
close(s->eth_fd);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int eth_close(struct sim *s)
|
|
||||||
{
|
|
||||||
if(s->eth_fd < 0)
|
|
||||||
close(s->eth_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void eth_write(struct sim *s, unsigned char *buf, int len)
|
|
||||||
{
|
|
||||||
write(s->eth_fd, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int eth_read(struct sim *s, unsigned char *buf)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct pollfd fds[1];
|
|
||||||
int n;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
fds[0].fd = s->eth_fd;
|
|
||||||
fds[0].events = POLLIN;
|
|
||||||
|
|
||||||
n = poll(fds, 1, 0);
|
|
||||||
if((n > 0) && ((fds[0].revents & POLLIN) == POLLIN)) {
|
|
||||||
len = read(s->eth_fd, buf, 1532);
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* VGA functions */
|
|
||||||
#ifdef WITH_VGA
|
|
||||||
|
|
||||||
SDL_Surface *screen;
|
|
||||||
SDL_Event event;
|
|
||||||
|
|
||||||
void vga_set_pixel(SDL_Surface *screen, int x, int y, char r, char g, char b)
|
|
||||||
{
|
|
||||||
unsigned int *pixmem32;
|
|
||||||
unsigned int color;
|
|
||||||
|
|
||||||
color = SDL_MapRGB(screen->format, r, g, b);
|
|
||||||
pixmem32 = (unsigned int*) screen->pixels + y*640 + x;
|
|
||||||
*pixmem32 = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vga_init(struct sim *s) {
|
|
||||||
if(SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
|
|
||||||
if(!(screen = SDL_SetVideoMode(640, 480+1, 32, SDL_HWSURFACE))) {
|
|
||||||
SDL_Quit();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int frame;
|
|
||||||
int hsync_wait_de = 1;
|
|
||||||
int vsync_wait_de = 1;
|
|
||||||
|
|
||||||
void vga_service(struct sim *s) {
|
|
||||||
int i;
|
|
||||||
if(VGA_HSYNC == 1 && hsync_wait_de == 0) {
|
|
||||||
x = 0;
|
|
||||||
y++;
|
|
||||||
hsync_wait_de = 1;
|
|
||||||
}
|
|
||||||
if(VGA_VSYNC == 1 && vsync_wait_de == 0) {
|
|
||||||
y = 0;
|
|
||||||
vsync_wait_de = 1;
|
|
||||||
for(i=0; i<frame; i++)
|
|
||||||
vga_set_pixel(screen, i%640, 480, 255, 255, 255);
|
|
||||||
frame++;
|
|
||||||
if(SDL_MUSTLOCK(screen))
|
|
||||||
SDL_UnlockSurface(screen);
|
|
||||||
SDL_Flip(screen);
|
|
||||||
if(SDL_MUSTLOCK(screen))
|
|
||||||
SDL_LockSurface(screen);
|
|
||||||
}
|
|
||||||
if(VGA_DE == 1) {
|
|
||||||
hsync_wait_de = 0;
|
|
||||||
vsync_wait_de = 0;
|
|
||||||
vga_set_pixel(screen, x, y, VGA_R, VGA_G, VGA_B);
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s->tick%1000 == 0) {
|
|
||||||
while(SDL_PollEvent(&event)) {
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_QUIT:
|
|
||||||
s->run = false;
|
|
||||||
break;
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
s->run = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int vga_close(struct sim *s) {
|
|
||||||
SDL_Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef WITH_SERIAL_PTY
|
|
||||||
int console_service(struct sim *s)
|
|
||||||
{
|
|
||||||
/* fpga --> console */
|
|
||||||
SERIAL_SOURCE_READY = 1;
|
|
||||||
if(SERIAL_SOURCE_VALID == 1) {
|
|
||||||
if(SERIAL_SOURCE_DATA == '\n')
|
|
||||||
putchar('\r');
|
|
||||||
putchar(SERIAL_SOURCE_DATA);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* console --> fpga */
|
|
||||||
SERIAL_SINK_VALID = 0;
|
|
||||||
if(s->tick%(1000) == 0) {
|
|
||||||
if(kbhit()) {
|
|
||||||
char c = getch();
|
|
||||||
if(c == 27 && !kbhit()) {
|
|
||||||
printf("\r\n");
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
SERIAL_SINK_VALID = 1;
|
|
||||||
SERIAL_SINK_DATA = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void console_init(struct sim *s)
|
|
||||||
{
|
|
||||||
FILE *f;
|
|
||||||
f = fopen("/tmp/simserial","r");
|
|
||||||
fscanf(f, "%[^\n]", s->serial_dev);
|
|
||||||
fclose(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console_open(struct sim *s)
|
|
||||||
{
|
|
||||||
s->serial_fd = open(s->serial_dev, O_RDWR);
|
|
||||||
if(s->serial_fd < 0) {
|
|
||||||
fprintf(stderr, " Could not open dev %s\n", s->serial_dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int console_close(struct sim *s)
|
|
||||||
{
|
|
||||||
if(s->serial_fd < 0)
|
|
||||||
close(s->serial_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console_write(struct sim *s, unsigned char *buf, int len)
|
|
||||||
{
|
|
||||||
write(s->serial_fd, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int console_read(struct sim *s, unsigned char *buf)
|
|
||||||
{
|
|
||||||
struct pollfd fds[1];
|
|
||||||
int n;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
fds[0].fd = s->serial_fd;
|
|
||||||
fds[0].events = POLLIN;
|
|
||||||
|
|
||||||
n = poll(fds, 1, 0);
|
|
||||||
if((n > 0) && ((fds[0].revents & POLLIN) == POLLIN)) {
|
|
||||||
len = read(s->serial_fd, buf, 1);
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int console_service(struct sim *s)
|
|
||||||
{
|
|
||||||
/* fpga --> console */
|
|
||||||
SERIAL_SOURCE_READY = 1;
|
|
||||||
if(SERIAL_SOURCE_VALID == 1) {
|
|
||||||
s->serial_tx_data = SERIAL_SOURCE_DATA;
|
|
||||||
console_write(s, &(s->serial_tx_data), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* console --> fpga */
|
|
||||||
SERIAL_SINK_VALID = 0;
|
|
||||||
if(console_read(s, &(s->serial_rx_data)))
|
|
||||||
{
|
|
||||||
SERIAL_SINK_VALID = 1;
|
|
||||||
SERIAL_SINK_DATA = s->serial_rx_data;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_ETH
|
|
||||||
int ethernet_service(struct sim *s) {
|
|
||||||
/* fpga --> tap */
|
|
||||||
ETH_SOURCE_READY = 1;
|
|
||||||
if(ETH_SOURCE_VALID == 1) {
|
|
||||||
s->eth_txbuffer[s->eth_txbuffer_len] = ETH_SOURCE_DATA;
|
|
||||||
s->eth_txbuffer_len++;
|
|
||||||
} else {
|
|
||||||
if(s->eth_last_source_valid) {
|
|
||||||
eth_write(s, s->eth_txbuffer, s->eth_txbuffer_len);
|
|
||||||
s->eth_txbuffer_len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s->eth_last_source_valid = ETH_SOURCE_VALID;
|
|
||||||
|
|
||||||
/* tap --> fpga */
|
|
||||||
if(s->eth_rxbuffer_len == 0) {
|
|
||||||
ETH_SINK_VALID = 0;
|
|
||||||
s->eth_rxbuffer_pos = 0;
|
|
||||||
s->eth_rxbuffer_len = eth_read(s, s->eth_rxbuffer);
|
|
||||||
} else {
|
|
||||||
if(s->eth_rxbuffer_pos < MAX(s->eth_rxbuffer_len, 60)) {
|
|
||||||
ETH_SINK_VALID = 1;
|
|
||||||
ETH_SINK_DATA = s->eth_rxbuffer[s->eth_rxbuffer_pos];
|
|
||||||
s->eth_rxbuffer_pos++;
|
|
||||||
} else {
|
|
||||||
ETH_SINK_VALID = 0;
|
|
||||||
s->eth_rxbuffer_len = 0;
|
|
||||||
memset(s->eth_rxbuffer, 0, 1532);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void sim_tick(struct sim *s)
|
|
||||||
{
|
|
||||||
SYS_CLK = s->tick%2;
|
|
||||||
dut->eval();
|
|
||||||
if(trace)
|
|
||||||
tfp->dump(s->tick);
|
|
||||||
s->tick++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_init(struct sim *s)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
s->tick = 0;
|
|
||||||
#ifdef SYS_RST
|
|
||||||
SYS_RST = 1;
|
|
||||||
SYS_CLK = 0;
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
sim_tick(s);
|
|
||||||
SYS_RST = 0;
|
|
||||||
#endif
|
|
||||||
s->start = clock();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv, char **env)
|
|
||||||
{
|
|
||||||
float speed;
|
|
||||||
|
|
||||||
#ifndef WITH_SERIAL_PTY
|
|
||||||
set_conio_terminal_mode();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
dut = new Vdut;
|
|
||||||
|
|
||||||
Verilated::traceEverOn(true);
|
|
||||||
tfp = new VerilatedVcdC;
|
|
||||||
dut->trace(tfp, 99);
|
|
||||||
tfp->open("dut.vcd");
|
|
||||||
|
|
||||||
struct sim s;
|
|
||||||
sim_init(&s);
|
|
||||||
|
|
||||||
#ifdef WITH_SERIAL_PTY
|
|
||||||
console_init(&s);
|
|
||||||
console_open(&s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_ETH
|
|
||||||
eth_init(&s, "/dev/net/tap0", "tap0"); // XXX get this from /tmp/simethernet
|
|
||||||
eth_open(&s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_VGA
|
|
||||||
if(vga_init(&s)) return 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s.run = true;
|
|
||||||
while(s.run) {
|
|
||||||
sim_tick(&s);
|
|
||||||
if(SYS_CLK) {
|
|
||||||
#ifdef WITH_SERIAL
|
|
||||||
if(console_service(&s) != 0)
|
|
||||||
s.run = false;
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_ETH
|
|
||||||
ethernet_service(&s);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_VGA
|
|
||||||
vga_service(&s);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.end = clock();
|
|
||||||
|
|
||||||
speed = (s.tick/2)/((s.end-s.start)/CLOCKS_PER_SEC);
|
|
||||||
|
|
||||||
printf("average speed: %3.3f MHz\n\r", speed/1000000);
|
|
||||||
|
|
||||||
tfp->close();
|
|
||||||
|
|
||||||
#ifdef WITH_SERIAL_PTY
|
|
||||||
console_close(&s);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_ETH
|
|
||||||
eth_close(&s);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_VGA
|
|
||||||
vga_close(&s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from litex.gen.fhdl.structure import Signal
|
||||||
|
from litex.gen.genlib.record import Record
|
||||||
from litex.build.generic_platform import GenericPlatform
|
from litex.build.generic_platform import GenericPlatform
|
||||||
from litex.build.sim import common, verilator
|
from litex.build.sim import common, verilator
|
||||||
|
|
||||||
|
@ -5,11 +7,29 @@ from litex.build.sim import common, verilator
|
||||||
class SimPlatform(GenericPlatform):
|
class SimPlatform(GenericPlatform):
|
||||||
def __init__(self, *args, toolchain="verilator", **kwargs):
|
def __init__(self, *args, toolchain="verilator", **kwargs):
|
||||||
GenericPlatform.__init__(self, *args, **kwargs)
|
GenericPlatform.__init__(self, *args, **kwargs)
|
||||||
|
self.sim_requested = []
|
||||||
if toolchain == "verilator":
|
if toolchain == "verilator":
|
||||||
self.toolchain = verilator.SimVerilatorToolchain()
|
self.toolchain = verilator.SimVerilatorToolchain()
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown toolchain")
|
raise ValueError("Unknown toolchain")
|
||||||
|
|
||||||
|
def request(self, name, number=None):
|
||||||
|
index = ""
|
||||||
|
if number is not None:
|
||||||
|
index = str(number)
|
||||||
|
obj = GenericPlatform.request(self, name, number=number)
|
||||||
|
siglist = []
|
||||||
|
if isinstance(obj, Signal):
|
||||||
|
siglist.append((name, obj.nbits, name))
|
||||||
|
elif isinstance(obj, Record):
|
||||||
|
for subsignal, dummy in obj.iter_flat():
|
||||||
|
subfname = subsignal.backtrace[-1][0]
|
||||||
|
prefix = "{}{}_".format(name, index)
|
||||||
|
subname = subfname.split(prefix)[1]
|
||||||
|
siglist.append((subname, subsignal.nbits, subfname))
|
||||||
|
self.sim_requested.append((name, index, siglist))
|
||||||
|
return obj
|
||||||
|
|
||||||
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
|
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
|
||||||
so = dict(common.sim_special_overrides)
|
so = dict(common.sim_special_overrides)
|
||||||
so.update(special_overrides)
|
so.update(special_overrides)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# This file is Copyright (c) 2015-2016 Florent Kermarrec <florent@enjoy-digital.fr>
|
# This file is Copyright (c) 2015-2016 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# 2017 Pierre-Olivier Vauboin <po@lambdaconcept.com>
|
||||||
# License: BSD
|
# License: BSD
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -10,116 +11,106 @@ from litex.build.generic_platform import *
|
||||||
|
|
||||||
|
|
||||||
sim_directory = os.path.abspath(os.path.dirname(__file__))
|
sim_directory = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
core_directory = os.path.join(sim_directory, 'core')
|
||||||
|
|
||||||
|
|
||||||
def _build_tb(platform, vns, serial, template):
|
def _generate_sim_h_struct(name, index, siglist):
|
||||||
def io_name(resource, subsignal=None):
|
content = ''
|
||||||
res = platform.lookup_request(resource)
|
|
||||||
if subsignal is not None:
|
|
||||||
res = getattr(res, subsignal)
|
|
||||||
return vns.get_name(res)
|
|
||||||
|
|
||||||
ios = """
|
content += 'struct pad_s {}{}[] = {{\n'.format(name, index)
|
||||||
#define SYS_CLK dut->{sys_clk}
|
for signame, sigbits, dummy in siglist:
|
||||||
""".format(sys_clk=io_name("sys_clk"))
|
content += ' {{ (char*)"{}", {}, NULL }},\n'.format(signame, sigbits)
|
||||||
|
content += ' { NULL, 0, NULL }\n'
|
||||||
|
content += '};\n\n'
|
||||||
|
|
||||||
if serial == "pty":
|
return content
|
||||||
ios += "#define WITH_SERIAL_PTY"
|
|
||||||
elif serial == "console":
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise ValueError
|
|
||||||
try:
|
|
||||||
ios += """
|
|
||||||
#define SERIAL_SOURCE_VALID dut->{serial_source_valid}
|
|
||||||
#define SERIAL_SOURCE_READY dut->{serial_source_ready}
|
|
||||||
#define SERIAL_SOURCE_DATA dut->{serial_source_data}
|
|
||||||
|
|
||||||
#define SERIAL_SINK_VALID dut->{serial_sink_valid}
|
|
||||||
#define SERIAL_SINK_READY dut->{serial_sink_ready}
|
|
||||||
#define SERIAL_SINK_DATA dut->{serial_sink_data}
|
|
||||||
""".format(
|
|
||||||
serial_source_valid=io_name("serial", "source_valid"),
|
|
||||||
serial_source_ready=io_name("serial", "source_ready"),
|
|
||||||
serial_source_data=io_name("serial", "source_data"),
|
|
||||||
|
|
||||||
serial_sink_valid=io_name("serial", "sink_valid"),
|
|
||||||
serial_sink_ready=io_name("serial", "sink_ready"),
|
|
||||||
serial_sink_data=io_name("serial", "sink_data"),
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
ios += """
|
|
||||||
#define ETH_SOURCE_VALID dut->{eth_source_valid}
|
|
||||||
#define ETH_SOURCE_READY dut->{eth_source_ready}
|
|
||||||
#define ETH_SOURCE_DATA dut->{eth_source_data}
|
|
||||||
|
|
||||||
#define ETH_SINK_VALID dut->{eth_sink_valid}
|
|
||||||
#define ETH_SINK_READY dut->{eth_sink_ready}
|
|
||||||
#define ETH_SINK_DATA dut->{eth_sink_data}
|
|
||||||
""".format(
|
|
||||||
eth_source_valid=io_name("eth", "source_valid"),
|
|
||||||
eth_source_ready=io_name("eth", "source_ready"),
|
|
||||||
eth_source_data=io_name("eth", "source_data"),
|
|
||||||
|
|
||||||
eth_sink_valid=io_name("eth", "sink_valid"),
|
|
||||||
eth_sink_ready=io_name("eth", "sink_ready"),
|
|
||||||
eth_sink_data=io_name("eth", "sink_data"),
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
ios += """
|
|
||||||
#define VGA_DE dut->{vga_de}
|
|
||||||
#define VGA_HSYNC dut->{vga_hsync}
|
|
||||||
#define VGA_VSYNC dut->{vga_vsync}
|
|
||||||
#define VGA_R dut->{vga_r}
|
|
||||||
#define VGA_G dut->{vga_g}
|
|
||||||
#define VGA_B dut->{vga_b}
|
|
||||||
""".format(
|
|
||||||
vga_de=io_name("vga", "de"),
|
|
||||||
vga_hsync=io_name("vga", "hsync"),
|
|
||||||
vga_vsync=io_name("vga", "vsync"),
|
|
||||||
vga_r=io_name("vga", "r"),
|
|
||||||
vga_g=io_name("vga", "g"),
|
|
||||||
vga_b=io_name("vga", "b"),
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
content = ""
|
|
||||||
f = open(template, "r")
|
|
||||||
done = False
|
|
||||||
for l in f:
|
|
||||||
content += l
|
|
||||||
if "/* ios */" in l and not done:
|
|
||||||
content += ios
|
|
||||||
done = True
|
|
||||||
|
|
||||||
f.close()
|
|
||||||
tools.write_to_file("dut_tb.cpp", content)
|
|
||||||
|
|
||||||
|
|
||||||
def _build_sim(platform, vns, build_name, include_paths, serial, verbose):
|
def _generate_sim_h(platform):
|
||||||
|
content = """\
|
||||||
|
#ifndef __SIM_CORE_H_
|
||||||
|
#define __SIM_CORE_H_
|
||||||
|
#include "pads.h"
|
||||||
|
|
||||||
|
"""
|
||||||
|
for args in platform.sim_requested:
|
||||||
|
content += _generate_sim_h_struct(*args)
|
||||||
|
|
||||||
|
content += """\
|
||||||
|
#ifndef __cplusplus
|
||||||
|
void lambdasim_init(void **out);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SIM_CORE_H_ */
|
||||||
|
"""
|
||||||
|
tools.write_to_file("dut_header.h", content)
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_sim_cpp_struct(name, index, siglist):
|
||||||
|
content = ''
|
||||||
|
|
||||||
|
for i, (signame, sigbits, sigfname) in enumerate(siglist):
|
||||||
|
content += ' {}{}[{}].signal = &dut->{};\n'.format(name, index, i, sigfname)
|
||||||
|
|
||||||
|
idx_int = 0 if not index else int(index)
|
||||||
|
content += ' lambdasim_register_pads({}{}, (char*)"{}", {});\n\n'.format(name, index, name, idx_int)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_sim_cpp(platform):
|
||||||
|
content = """\
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "Vdut.h"
|
||||||
|
#include <verilated.h>
|
||||||
|
#include "dut_header.h"
|
||||||
|
|
||||||
|
extern "C" void lambdasim_init(void **out)
|
||||||
|
{
|
||||||
|
Vdut *dut;
|
||||||
|
|
||||||
|
dut = new Vdut;
|
||||||
|
|
||||||
|
"""
|
||||||
|
for args in platform.sim_requested:
|
||||||
|
content += _generate_sim_cpp_struct(*args)
|
||||||
|
|
||||||
|
content += """\
|
||||||
|
*out=dut;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
tools.write_to_file("dut_init.cpp", content)
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_sim_variables(include_paths):
|
||||||
include = ""
|
include = ""
|
||||||
for path in include_paths:
|
for path in include_paths:
|
||||||
include += "-I"+path+" "
|
include += "-I"+path+" "
|
||||||
|
|
||||||
build_script_contents = """# Autogenerated by LiteX
|
content = """\
|
||||||
rm -rf obj_dir/
|
SRC_DIR = {}
|
||||||
verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp -LDFLAGS "-lpthread -lSDL" -trace {include}
|
INC_DIR = {}
|
||||||
make -j -C obj_dir/ -f Vdut.mk Vdut
|
""".format(core_directory, include)
|
||||||
|
tools.write_to_file("variables.mak", content)
|
||||||
|
|
||||||
""".format(
|
|
||||||
disable_warnings="-Wno-fatal",
|
def _generate_sim_config(config):
|
||||||
include=include)
|
content = config.get_json()
|
||||||
|
tools.write_to_file("sim_config.js", content)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_sim(platform, build_name, verbose):
|
||||||
|
makefile = os.path.join(core_directory, 'Makefile')
|
||||||
|
build_script_contents = """\
|
||||||
|
rm -rf obj_dir/
|
||||||
|
make -C . -f {}
|
||||||
|
mkdir -p modules && cp obj_dir/*.so modules
|
||||||
|
""".format(makefile)
|
||||||
build_script_file = "build_" + build_name + ".sh"
|
build_script_file = "build_" + build_name + ".sh"
|
||||||
tools.write_to_file(build_script_file, build_script_contents, force_unix=True)
|
tools.write_to_file(build_script_file, build_script_contents, force_unix=True)
|
||||||
|
|
||||||
_build_tb(platform, vns, serial, os.path.join(sim_directory, "dut_tb.cpp"))
|
|
||||||
p = subprocess.Popen(["bash", build_script_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
p = subprocess.Popen(["bash", build_script_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
output, _ = p.communicate()
|
output, _ = p.communicate()
|
||||||
output = output.decode('utf-8')
|
output = output.decode('utf-8')
|
||||||
|
@ -134,7 +125,8 @@ make -j -C obj_dir/ -f Vdut.mk Vdut
|
||||||
|
|
||||||
|
|
||||||
def _run_sim(build_name):
|
def _run_sim(build_name):
|
||||||
run_script_contents = """obj_dir/Vdut
|
run_script_contents = """\
|
||||||
|
sudo obj_dir/Vdut
|
||||||
"""
|
"""
|
||||||
run_script_file = "run_" + build_name + ".sh"
|
run_script_file = "run_" + build_name + ".sh"
|
||||||
tools.write_to_file(run_script_file, run_script_contents, force_unix=True)
|
tools.write_to_file(run_script_file, run_script_contents, force_unix=True)
|
||||||
|
@ -145,8 +137,9 @@ def _run_sim(build_name):
|
||||||
|
|
||||||
class SimVerilatorToolchain:
|
class SimVerilatorToolchain:
|
||||||
def build(self, platform, fragment, build_dir="build", build_name="top",
|
def build(self, platform, fragment, build_dir="build", build_name="top",
|
||||||
toolchain_path=None, serial="console", run=True, verbose=True):
|
toolchain_path=None, serial="console", run=True, verbose=True,
|
||||||
tools.mkdir_noerror(build_dir)
|
sim_config=None):
|
||||||
|
os.makedirs(build_dir, exist_ok=True)
|
||||||
os.chdir(build_dir)
|
os.chdir(build_dir)
|
||||||
|
|
||||||
if not isinstance(fragment, _Fragment):
|
if not isinstance(fragment, _Fragment):
|
||||||
|
@ -163,7 +156,12 @@ class SimVerilatorToolchain:
|
||||||
if path not in include_paths:
|
if path not in include_paths:
|
||||||
include_paths.append(path)
|
include_paths.append(path)
|
||||||
include_paths += platform.verilog_include_paths
|
include_paths += platform.verilog_include_paths
|
||||||
_build_sim(platform, v_output.ns, build_name, include_paths, serial, verbose)
|
_generate_sim_h(platform)
|
||||||
|
_generate_sim_cpp(platform)
|
||||||
|
_generate_sim_variables(include_paths)
|
||||||
|
if sim_config:
|
||||||
|
_generate_sim_config(sim_config)
|
||||||
|
_build_sim(platform, build_name, verbose)
|
||||||
|
|
||||||
if run:
|
if run:
|
||||||
_run_sim(build_name)
|
_run_sim(build_name)
|
||||||
|
|
Loading…
Reference in New Issue