build/sim: add jtagremote module (thanks LamdaConcept)
This commit is contained in:
parent
57b8bdd530
commit
1d9c55888f
|
@ -0,0 +1,5 @@
|
|||
include ../variables.mak
|
||||
|
||||
all: $(OBJ_DIR)/jtagremote.so
|
||||
|
||||
include ../rules.mak
|
|
@ -0,0 +1,263 @@
|
|||
#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 *tdi;
|
||||
char *tdo;
|
||||
char *tck;
|
||||
char *tms;
|
||||
char *sys_clk;
|
||||
struct event *ev;
|
||||
char databuf[2048];
|
||||
int data_start;
|
||||
int datalen;
|
||||
int cntticks;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct event_base *base;
|
||||
|
||||
int litex_sim_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 litex_sim_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 jtagremote_start(void *b)
|
||||
{
|
||||
base = (struct event_base *)b;
|
||||
printf("[jtagremote] 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)
|
||||
{
|
||||
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 jtagremote_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 = litex_sim_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 jtagremote_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;
|
||||
printf("plist name: %s\n", plist->name);
|
||||
if(!strcmp(plist->name, "jtag")) {
|
||||
litex_sim_module_pads_get(pads, "tck", (void**)&s->tck);
|
||||
litex_sim_module_pads_get(pads, "tdi", (void**)&s->tdi);
|
||||
litex_sim_module_pads_get(pads, "tdo", (void**)&s->tdo);
|
||||
litex_sim_module_pads_get(pads, "tms", (void**)&s->tms);
|
||||
}
|
||||
|
||||
if(!strcmp(plist->name, "sys_clk"))
|
||||
litex_sim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
}
|
||||
static int jtagremote_tick(void *sess)
|
||||
{
|
||||
char c, val;
|
||||
int ret = RC_OK;
|
||||
|
||||
struct session_s *s = (struct session_s*)sess;
|
||||
if(*s->sys_clk == 0)
|
||||
return RC_OK;
|
||||
|
||||
s->cntticks++;
|
||||
if(s->cntticks % 10)
|
||||
return RC_OK;
|
||||
|
||||
if(s->datalen)
|
||||
{
|
||||
c = s->databuf[s->data_start];
|
||||
|
||||
if((c >= '0') && (c <= '7')){
|
||||
*s->tck = ((c - '0') >> 2) & 1;
|
||||
*s->tms = ((c - '0') >> 1) & 1;
|
||||
*s->tdi = (c - '0') & 1;
|
||||
}
|
||||
if(c == 'R'){
|
||||
val = *s->tdo + '0';
|
||||
if(-1 == write(s->fd, &val, 1)) {
|
||||
eprintf("Error writing on socket\n");
|
||||
ret = RC_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
s->data_start = (s->data_start + 1) % 2048;
|
||||
s->datalen--;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ext_module_s ext_mod = {
|
||||
"jtagremote",
|
||||
jtagremote_start,
|
||||
jtagremote_new,
|
||||
jtagremote_add_pads,
|
||||
NULL,
|
||||
jtagremote_tick
|
||||
};
|
||||
|
||||
int litex_sim_ext_module_init(int (*register_module)(struct ext_module_s *))
|
||||
{
|
||||
int ret = RC_OK;
|
||||
ret = register_module(&ext_mod);
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue