litex/build/sim: introduce new simulator with modules support (thanks lambdaconcept)

This commit is contained in:
Pierre-Olivier Vauboin 2017-06-28 16:10:34 +02:00 committed by Florent Kermarrec
parent 6631aa5385
commit 8510b12e93
29 changed files with 3459 additions and 593 deletions

View File

@ -20,6 +20,8 @@ from litedram.core.controller import ControllerSettings
from liteeth.phy.model import LiteEthPHYModel
from liteeth.core.mac import LiteEthMAC
from litex.build.sim.config import SimConfig
class BaseSoC(SoCSDRAM):
def __init__(self, **kwargs):
platform = sim.Platform()
@ -92,10 +94,15 @@ def main():
help="enable Ethernet support")
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
soc = cls(**soc_sdram_argdict(args))
builder = Builder(soc, **builder_argdict(args))
builder.build()
builder.build(sim_config=scfg)
if __name__ == "__main__":

42
litex/build/sim/config.py Normal file
View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
include ../variables.mak
all: $(OBJ_DIR)/clocker.so
include ../rules.mak

View File

@ -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;
}

View File

@ -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 $@ $<

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,5 @@
include ../variables.mak
all: $(OBJ_DIR)/serial2console.so
include ../rules.mak

View File

@ -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;
}

View File

@ -0,0 +1,5 @@
include ../variables.mak
all: $(OBJ_DIR)/serial2tcp.so
include ../rules.mak

View File

@ -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;
}

View File

@ -0,0 +1,5 @@
CC = gcc
CFLAGS = -Wall -O3 -ggdb -fPIC -Werror
LDFLAGS = -levent -shared -fPIC
OBJ_DIR ?= .

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

244
litex/build/sim/core/sim.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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.sim import common, verilator
@ -5,11 +7,29 @@ from litex.build.sim import common, verilator
class SimPlatform(GenericPlatform):
def __init__(self, *args, toolchain="verilator", **kwargs):
GenericPlatform.__init__(self, *args, **kwargs)
self.sim_requested = []
if toolchain == "verilator":
self.toolchain = verilator.SimVerilatorToolchain()
else:
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):
so = dict(common.sim_special_overrides)
so.update(special_overrides)

View File

@ -1,4 +1,5 @@
# This file is Copyright (c) 2015-2016 Florent Kermarrec <florent@enjoy-digital.fr>
# 2017 Pierre-Olivier Vauboin <po@lambdaconcept.com>
# License: BSD
import os
@ -10,116 +11,106 @@ from litex.build.generic_platform import *
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 io_name(resource, subsignal=None):
res = platform.lookup_request(resource)
if subsignal is not None:
res = getattr(res, subsignal)
return vns.get_name(res)
def _generate_sim_h_struct(name, index, siglist):
content = ''
ios = """
#define SYS_CLK dut->{sys_clk}
""".format(sys_clk=io_name("sys_clk"))
content += 'struct pad_s {}{}[] = {{\n'.format(name, index)
for signame, sigbits, dummy in siglist:
content += ' {{ (char*)"{}", {}, NULL }},\n'.format(signame, sigbits)
content += ' { NULL, 0, NULL }\n'
content += '};\n\n'
if serial == "pty":
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)
return 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 = ""
for path in include_paths:
include += "-I"+path+" "
build_script_contents = """# Autogenerated by LiteX
rm -rf obj_dir/
verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp -LDFLAGS "-lpthread -lSDL" -trace {include}
make -j -C obj_dir/ -f Vdut.mk Vdut
content = """\
SRC_DIR = {}
INC_DIR = {}
""".format(core_directory, include)
tools.write_to_file("variables.mak", content)
""".format(
disable_warnings="-Wno-fatal",
include=include)
def _generate_sim_config(config):
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"
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)
output, _ = p.communicate()
output = output.decode('utf-8')
@ -134,7 +125,8 @@ make -j -C obj_dir/ -f Vdut.mk Vdut
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"
tools.write_to_file(run_script_file, run_script_contents, force_unix=True)
@ -145,8 +137,9 @@ def _run_sim(build_name):
class SimVerilatorToolchain:
def build(self, platform, fragment, build_dir="build", build_name="top",
toolchain_path=None, serial="console", run=True, verbose=True):
tools.mkdir_noerror(build_dir)
toolchain_path=None, serial="console", run=True, verbose=True,
sim_config=None):
os.makedirs(build_dir, exist_ok=True)
os.chdir(build_dir)
if not isinstance(fragment, _Fragment):
@ -163,7 +156,12 @@ class SimVerilatorToolchain:
if path not in include_paths:
include_paths.append(path)
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:
_run_sim(build_name)