Simulator (xsim) can't load plugin

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
IgorLopez
Member++
Posts: 25
Joined: Tue Mar 11, 2014 8:16 pm

Simulator (xsim) can't load plugin

Post by IgorLopez »

Hi

I am trying to simulate an xcore application that is using the I2C library (lib_i2c) as a Slave towards a Raspberry PI (which is acting as Master).

For this I did a plugin in the same way as the ExamplePlugin but with plugin_clock adapted to act as a Raspberry PI Master sending out an address and waiting for an ACK from the slave.

When starting the simulation I get this:
~/xmosworkspace/i2cTest/bin$ xsim --plugin I2CTestPlugin.o "0 XOD23 XOD13" i2cTest.xe
I2CTestPlugin.o: only ET_DYN and ET_EXEC can be loaded
ERROR: unable to open plugin 'I2CTestPlugin.o'
but the plugin is of course there:
~/xmosworkspace/i2cTest/bin$ ls
I2CTestPlugin.o i2cTest.xe
The plugin was built as:
~/Tools/XMOS/xTIMEcomposer/Community_14.0.3/src/plugins/I2CTestPlugin$ make -f MakefileUnixGPP.mak
g++ -g -fPIC -O3 -Wall -Wsign-compare -Wpointer-arith -c I2CTestPlugin.cpp -o I2CTestPlugin.o -I../../../include
g++ I2CTestPlugin.o -shared -o ../../../lib/I2CTestPlugin.so -lc -ldl -lstdc++
The actual plugin code is rather simple (copied most of the stuff from ExamplePlugin.cpp):

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include "I2CTestPlugin.h"

#define MAX_INSTANCES 1
#define MAX_BYTES 1024
#define CHECK_STATUS if (status != XSI_STATUS_OK) return status

/*
 * Types
 */
struct LoopbackInstance
{
  XsiCallbacks *xsi;
  const char *package;
  const char *sda;
  const char *scl;
};

/*
 * Static data
 */
static size_t s_num_instances = 0;
static LoopbackInstance s_instances[MAX_INSTANCES];
static unsigned int timeStamp_us = 0; // increments each us;
static unsigned int counter = 0; // used to increment timeStamp_us every 100'th call (100 MHz clock)
/* This plugin is acting as an I2C Master and is driving the scl pin indepenent
 * of the I2C Slave on the Startkit. It will drive the sda during address and
 * RW bit but the release the pin to the Slave during the ACK bit.
 */
const unsigned int scl_switchTimes_us[20] = {10, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 110};
const unsigned int sda_switchTimes_us[5]  = {5,      23,     33,                             73,     83};
static unsigned scl_level = 1; // start with pin high
static unsigned sda_level = 1; // start with pin high
static unsigned int scl_index = 0;
static unsigned int sda_index = 0;
const unsigned int scl_ACK_start_index = 14;
const unsigned int scl_ACK_end_index = 16;
const unsigned int scl_last_index = sizeof(scl_switchTimes_us)/sizeof(scl_switchTimes_us[0]);
static unsigned int sda_ACK_counter = 0;
static unsigned sda_slave_is_ACK = 0;
static unsigned slave_should_ack = 0;

/*
 * Static functions
 */
static void print_usage();
static XsiStatus split_args(const char *args, char *argv[]);

/*
 * Create
 */
XsiStatus plugin_create(void **instance, XsiCallbacks *xsi, const char *arguments)
{
  if (s_num_instances >= MAX_INSTANCES) {
    fprintf(stderr, "ERROR: too many instances of plugin (max %d)\n", MAX_INSTANCES);
    return XSI_STATUS_INVALID_INSTANCE;
  }
  assert(CHECK_INTERFACE_VERSION(xsi));
  // Use the entry in the instances list to identify this instance
  *instance = (void*)s_num_instances;

  char *argv[3];
  XsiStatus status = split_args(arguments, argv);
  if (status != XSI_STATUS_OK) {
    print_usage();
    return status;
  }

  // Stores pin information
  s_instances[s_num_instances].package = argv[0];
  s_instances[s_num_instances].sda = argv[1];
  s_instances[s_num_instances].scl = argv[2];

  s_instances[s_num_instances].xsi = xsi;
  s_num_instances++;
  return XSI_STATUS_OK;
}

/*
 * Clock
 */
XsiStatus plugin_clock(void *instance)
{
  size_t instance_num = (size_t)instance;
  if (instance_num >= s_num_instances) {
    return XSI_STATUS_INVALID_INSTANCE;
  }

  XsiStatus status = XSI_STATUS_OK;

  XsiCallbacks *xsi = s_instances[instance_num].xsi;
  const char *package = s_instances[instance_num].package;
  const char *sda     = s_instances[instance_num].sda;
  const char *scl   = s_instances[instance_num].scl;

  unsigned value = 0;
  unsigned int sda_driving = 0;
  unsigned int scl_driving = 0;

  status = xsi->is_pin_driving(package, sda, &sda_driving);
  CHECK_STATUS;
  status = xsi->is_pin_driving(package, scl, &scl_driving);
  CHECK_STATUS;
  // Check that slave is not driving scl
  if (1 == scl_driving) {
    fprintf(stderr, "Slave is driving the SCL pin!\n");
    return XSI_STATUS_INVALID_PIN;
  }

  // Handle time
  if (100 == counter) {
    timeStamp_us++;
    counter = 0;
  }

  // Handle scl
  if (sizeof(scl_switchTimes_us) > scl_index) {
    if (scl_switchTimes_us[scl_index] <= timeStamp_us) {
      // switch scl
      if (1 > scl_level) {
        // scl is low, set it high
        scl_level = 1;
      }
      else {
        // scl is high, set it low
        scl_level = 0;
      }
      // incremt to next index
      scl_index++;
    }
  }

  // Handle sda when driving for address bits
  if (sizeof(sda_switchTimes_us) > sda_index) {
    if (sda_switchTimes_us[sda_index] <= timeStamp_us) {
      // switch sda
      if (1 > sda_level) {
        // sda is low, set it high
        sda_level = 1;
      }
      else {
        // sda is high, set it low
        sda_level = 0;
      }
      // incremt to next index
      sda_index++;
    }
  }

  // Check that slave is driving SDA low during the ACK phase
  if ((scl_switchTimes_us[scl_ACK_start_index] <= timeStamp_us) &&
      (scl_switchTimes_us[scl_ACK_end_index] > timeStamp_us)) {
    status = xsi->sample_pin(package, sda, &value);
    CHECK_STATUS;
    slave_should_ack = 1;
    if ((1 == sda_driving) && (0 == value)) {
      sda_ACK_counter++;
      sda_slave_is_ACK = 1;
    }
    // If slave started ACK it must keep ACK until begin of stop bit
    if ((1 == sda_slave_is_ACK) && (1 == value)) {
      fprintf(stderr, "Slave dropped ACK during the ninth bit!\n");
    }
  }

  // Check that slave did ACK
  if (scl_switchTimes_us[scl_ACK_end_index] < timeStamp_us) {
    slave_should_ack = 0;
    if (0 == sda_slave_is_ACK) {
      fprintf(stderr, "Slave did not ACK during the ninth bit!\n");
    }
  }

  // handle the stop bit
  if ((scl_switchTimes_us[scl_ACK_end_index] < timeStamp_us) &&
      (scl_switchTimes_us[scl_last_index-1]+5 > timeStamp_us)) {
    sda_level = 0;
  }

  if (scl_switchTimes_us[scl_last_index-1]+5 <= timeStamp_us) {
    sda_level = 1;
  }

  // drive the pins, scl all the time
  status = xsi->drive_pin(package, scl, scl_level);
  if (0 == slave_should_ack) {
    // drive sda when slave is not ACK
    status = xsi->drive_pin(package, sda, sda_level);
  }

  // Increment counter for next sim step
  counter++;

  return status;
}

/*
 * Notify
 */
XsiStatus plugin_notify(void *instance, int type, unsigned arg1, unsigned arg2)
{
  return XSI_STATUS_OK;
}

/*
 * Terminate
 */
XsiStatus plugin_terminate(void *instance)
{
  if ((size_t)instance >= s_num_instances) {
    return XSI_STATUS_INVALID_INSTANCE;
  }
  return XSI_STATUS_OK;
}

/*
 * Usage
 */
static void print_usage()
{
  fprintf(stderr, "Usage:\n");
  fprintf(stderr, "  I2CTestPlugin.dll/so <package> <sda pin> <scl pin>\n");
}

/*
 * Split args
 */
static XsiStatus split_args(const char *args, char *argv[])
{
  char buf[MAX_BYTES];

  int arg_num = 0;
  while (arg_num < 3) {
    char *buf_ptr = buf;

    while (isspace(*args))
      args++;

    if (*args == '\0')
      return XSI_STATUS_INVALID_ARGS;

    while (*args != '\0' && !isspace(*args))
      *buf_ptr++ = *args++;

    *buf_ptr = '\0';
    argv[arg_num] = strdup(buf);
    arg_num++;
  }

  while (isspace(*args))
    args++;

  if (arg_num != 3 || *args != '\0')
    return XSI_STATUS_INVALID_ARGS;
  else
    return XSI_STATUS_OK;
}
Is there anbody having an idea on what the problem could be?

/Igor


IgorLopez
Member++
Posts: 25
Joined: Tue Mar 11, 2014 8:16 pm

Post by IgorLopez »

I have now tried with the provided examples and get the same problem:

The example plugin:
~/Tools/XMOS/xTIMEcomposer/Community_14.0.3/src/plugins/ExamplePlugin$ make -f MakefileUnix.mak
g++ -g -fPIC -O3 -Wall -Wsign-compare -Wpointer-arith -c ExamplePlugin.cpp -o ExamplePlugin.o -I../../../include
g++ ExamplePlugin.o -shared -o ../../../lib/ExamplePlugin.so -lc -ldl -lstdc++
Running the simulator with the plugin:
~/xmosworkspace/ExamplePluginTest/bin$ xsim --max-cycles 100000 --plugin ExamplePlugin.o "0 X0D00 0 X0D01" ExamplePluginTest.xe
ExamplePlugin.o: only ET_DYN and ET_EXEC can be loaded
ERROR: unable to open plugin 'ExamplePlugin.o'
p1 -> 0 -> p2 ok
p1 -> 1 -> p2 error
p2 -> 0 -> p1 ok
p2 -> 1 -> p1 error
Note, I did not use the provided makefile since I took the one when I created a new xtimecomposer project targeting the StartKit.

I get the same error as with my own plugin.
- ExamplePlugin.o: only ET_DYN and ET_EXEC can be loaded
- ERROR: unable to open plugin 'ExamplePlugin.o

Is my PC build environment not set up properly for building the plugins?
srinie
XCore Addict
Posts: 158
Joined: Thu Mar 20, 2014 8:04 am

Post by srinie »

Hi, can you please specify your host details?
IgorLopez
Member++
Posts: 25
Joined: Tue Mar 11, 2014 8:16 pm

Post by IgorLopez »

I am running Ubuntu,
uname -a
Linux LOPEZ-DT 3.16.0-43-generic #58~14.04.1-Ubuntu SMP Mon Jun 22 10:21:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

If you need more specifics regarding installed packages and so forth just ask.
What I can guess is of interrest is the tools and libs used when building.
g++ -g -fPIC -O3 -Wall -Wsign-compare -Wpointer-arith -c ExamplePlugin.cpp -o ExamplePlugin.o -I../../../include
g++ ExamplePlugin.o -shared -o ../../../lib/ExamplePlugin.so -lc -ldl -lstdc++

dpkg --get-selections |grep -v deinstall|grep g++
g++
g++-4.8

dpkg --get-selections |grep -v deinstall|grep stdc
libstdc++-4.8-dev:amd64
libstdc++6:amd64
libstdc++6:i386

ldconfig -p|grep libstdc
libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6
User avatar
kris
Experienced Member
Posts: 84
Joined: Mon Jan 18, 2010 2:52 pm

Post by kris »

Hi Igor.

I think you are passing the object file to xsim on the command line instead of the plugin itself. Try passing ExamplePlugin.so instead of ExamplePlugin.o.

Hope this helps,
Cheers,
Kris.
IgorLopez
Member++
Posts: 25
Joined: Tue Mar 11, 2014 8:16 pm

Post by IgorLopez »

Thanks Kris,

You are of course right, changing from .o to .so solved the problem.
Now I can go back to test my I2C setup.

/Igor
Post Reply