On 12/08/2013 02:09 AM, David Koontz wrote:
On 8 Dec 2013, at 2:00 am, Brian Drummond<br...@shapes.demon.co.uk>  wrote:

The specific import of this - to ghdl - is that ghdl's VHPI interface
really only supports procedure/function calls between languages.

So if you can structure the interaction such that a VHDL process calls a
C function or procedure (void function), that process will block until
the function's return, and that takes zero simulation time (occurs
within a delta cycle).

Thus with the VHDL side in control, the simulation cycle controls the
timing.
There was a ghdl-discuss thread earlier this year, mid April "Calling functions 
written in VHDL from a linked C-language-compiled binary" which got slightly 
derailed by a post by René Doß, where I modified an assignment statement making a foreign 
call from:

Oh I remember it.

Yes I would make a similary connection but inverse. I had to verificate a CPU written in VHDL.

background:
I have developed a 32bit MIPS softcore. In a development phase I would control the simulator with a local Ethernet port. I had written a gdb-server in C a but I could not change signals in VHDL/GHDL for outside.

The GDB server started in the addition process in the testbench.

  gdb_init : process
  variable i: integer ;
  begin
    i:=wait_for_connect(2020);
  wait;
  end process;

The C entry code and VHDL code is attached on this email.

I stopped this debugging tool because I could not initiate signal changes by the C code.


Now I am over this development phase.
The process is a little bit others.
I have a converter tool, that produce from an elf file (compiled and Linked Software) an VHDL file. The OP-codes are lockated in a Block Ram. After all files are VHDL files and I have to simulate only VHDL files.



The Softcore can you found at:
 http://www.dossmatik.de/mais-cpu.html

The Mais CPU runs MIPS-I opcodes. And you can also use gcc as C compiler.



René Doß
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netdb.h>

#include <pthread.h>


#define GDBSTUB_EXECUTION_BREAKPOINT (0xac1)
#define GDBSTUB_TRACE (0xac2)
#define GDBSTUB_USER_BREAK (0xac3)

static int listen_socket_fd;
static int socket_fd;





static int hex(char ch)
{
   if ((ch >= 'a') && (ch <= 'f')) return(ch - 'a' + 10);
   if ((ch >= '0') && (ch <= '9')) return(ch - '0');
   if ((ch >= 'A') && (ch <= 'F')) return(ch - 'A' + 10);
   return(-1);
}

static void put_debug_char(char ch)
{
  send(socket_fd, &ch, 1, 0);
}

static char get_debug_char(void)
{
   char ch;
   
   recv(socket_fd, &ch, 1, 0);
   
   return(ch);
}

static const char hexchars[]="0123456789abcdef";

static void put_reply(char* buffer)
{
   unsigned char csum;
   int i;
      
   do
     {
       put_debug_char('$');
       
       csum = 0;
       
       i = 0;
       while (buffer[i] != 0)
         {
            put_debug_char(buffer[i]);
            csum = csum + buffer[i];
            i++;
         }
       
       put_debug_char('#');
       put_debug_char(hexchars[csum >> 4]);
       put_debug_char(hexchars[csum % 16]);
     } while (get_debug_char() != '+');
}

static void get_command(char* buffer)
{
   unsigned char checksum;
   unsigned char xmitcsum;
   char ch;
   unsigned int count;
   unsigned int i;
   
   do
     {
       while ((ch = get_debug_char()) != '$');
       
       checksum = 0;
       xmitcsum = 0;
       count = 0;
   
       while (1)
         {
            ch = get_debug_char();
            if (ch == '#') break;
            checksum = checksum + ch;
            buffer[count] = ch;
            count++;
         }
       buffer[count] = 0;
       
       if (ch == '#')
         {
            xmitcsum = hex(get_debug_char()) << 4;
            xmitcsum += hex(get_debug_char());
            if (checksum != xmitcsum)
              {
           //      BX_INFO (("Bad checksum"));
              }
         }
       
       if (checksum != xmitcsum)
         {
            put_debug_char('-');
         }
       else
         {
            put_debug_char('+');
            if (buffer[2] == ':')
              {
                 put_debug_char(buffer[0]);
                 put_debug_char(buffer[1]);
                 count = strlen(buffer);
                 for (i = 3; i <= count; i++)
                   {
                      buffer[i - 3] = buffer[i];
                   }
              }
         }
     } while (checksum != xmitcsum);
}

void hex2mem(char* buf, unsigned char* mem, int count)
{
   int i;
   unsigned char ch;
   
   for (i = 0; i<count; i++)
     {
       ch = hex(*buf++) << 4;
       ch = ch + hex(*buf++);
       *mem = ch;
       mem++;
     }
}

char* mem2hex(char* mem, char* buf, int count)
{
   int i;
   unsigned char ch;
   
   for (i = 0; i<count; i++)
     {
       ch = *mem;
       mem++;
       *buf = hexchars[ch >> 4];
       buf++;
       *buf = hexchars[ch % 16];
       buf++;
     }
   *buf = 0;
   return(buf);
}

static int continue_thread = -1;
static int other_thread = 0;

#define NUMREGS (18)
#define NUMREGSBYTES (NUMREGS * 4)
static int registers[NUMREGS];

#define MAX_BREAKPOINTS (255)
static int breakpoints[MAX_BREAKPOINTS] = {0,};
static int nr_breakpoints = 0;

static int stub_trace_flag = 0;

static int instr_count = 0;

static int saved_eip = 0;

int bx_gdbstub_check(unsigned int pc)
{
   unsigned int i;
   unsigned char ch;
   long arg;
   int r;
   fd_set fds;
   struct timeval tv = {0, 0};

   instr_count++;
   
   if ((instr_count % 500) == 0)
     {

       FD_ZERO(&fds);
       FD_SET(socket_fd, &fds);
        r = select(socket_fd + 1, &fds, NULL, NULL, &tv);
       if (r == 1)
         {
           r = recv(socket_fd, &ch, 1, 0);
         }

       if (r == 1)
         {
          //  BX_INFO (("Got byte %x", (unsigned int)ch));
    //        last_stop_reason = GDBSTUB_USER_BREAK;
    //        return(GDBSTUB_USER_BREAK);
         }
     }
   
   // why is trace before breakpoints? does that mean it would never
   // hit a breakpoint during tracing?
   if (stub_trace_flag == 1)
     {
   //    last_stop_reason = GDBSTUB_TRACE;
   //    return(GDBSTUB_TRACE);
     }
   for (i = 0; i < nr_breakpoints; i++)
     {
       if (pc == breakpoints[i])
         {
         //   BX_INFO (("found breakpoint at %x", pc));
         //   last_stop_reason = GDBSTUB_EXECUTION_BREAKPOINT;
            return(GDBSTUB_EXECUTION_BREAKPOINT);
         }
     }
 //  last_stop_reason = GDBSTUB_STOP_NO_REASON;
 //  return(GDBSTUB_STOP_NO_REASON);
}

static int remove_breakpoint(int addr, int len)
{
   unsigned int i;
   
   if (len != 4)
     {
       return(0);
     }
   
   for (i = 0; i < MAX_BREAKPOINTS; i++)
     {
       if (breakpoints[i] == addr)
         {
   //         BX_INFO (("Removing breakpoint at %x", addr));
            breakpoints[i] = 0;
            return(1);
         }
     }
   return(0);
}

static void insert_breakpoint(int addr)
{
   unsigned int i;
   
//   BX_INFO (("setting breakpoint at %x", addr));
   
   for (i = 0; i < MAX_BREAKPOINTS; i++)
     {
       if (breakpoints[i] == 0)
         {
            breakpoints[i] = addr;
            if (i >= nr_breakpoints)
              {
                 nr_breakpoints = i + 1;
              }
            return;
         }
     }
//   BX_INFO (("No slot for breakpoint"));
}

static void write_signal(char* buf, int signal)
{
   buf[0] = hexchars[signal >> 4];
   buf[1] = hexchars[signal % 16];
   buf[2] = 0;
}

static int access_linear(int laddress,
                        unsigned len,
                        unsigned int rw,
                        int* data)
{
  int phys;
  int valid;
   
   if (((laddress & 0xfff) + len) > 4096)
     {
       valid = access_linear(laddress,
                             4096 - (laddress & 0xfff),
                             rw,
                             data);
       if (!valid)
         {
            return(valid);
         }
   //    valid = access_linear(laddress,
     //                        len + (laddress & 0xfff) - 4096,
       //                      rw,
         //                    (Bit8u *)((unsigned int)data +
           //                           (laddress & 0xfff)));
       return(valid);
     }
   
 //  bx_memsys.pluginMmu->dbg_xlate_linear2phy((Bit32u)laddress,
   //                                    (Bit32u*)&phys,
     //                                  (bx_bool*)&valid);
   if (!valid)
     {
       return(0);
     }
   
 //  if (rw == BX_READ)
   //  {
//       valid = BX_MEM(0)->dbg_fetch_mem(phys, len, data);
//     }
//   else
//     {
///       valid = BX_MEM(0)->dbg_set_mem(phys, len, data);
//     }
   return(valid);
}










 void* debug_loop()
{
   printf ("debug_loop\n");	
   char buffer[1024];
   char obuf[1024];
   int ne;
   unsigned char mem[1024];
   
   ne = 0;
   
   while (ne == 0)
     {
       get_command(buffer);
        printf ("get_buffer %s", buffer);
       
       switch (buffer[0])
         {
          case 'c':
              {
                 char buf[255];
#if 0
int new_eip;
if (buffer[1] != 0)
{
new_eip = atoi(buffer + 1);
//BX_INFO (("continuing at %x", new_eip));
for (int i=0; i<BX_SMP_PROCESSORS; i++) {
BX_CPU(i)->invalidate_prefetch_q();
}
saved_eip = EIP;
BX_CPU(0)->dword.eip = new_eip;
}
#endif
                 stub_trace_flag = 0;
       //          bx_cpu.cpu_loop(-1);
//        //          DEV_vga_refresh();

#if 0
if (buffer[1] != 0)
{
bx_cpu.invalidate_prefetch_q();
BX_CPU_THIS_PTR dword.eip = saved_eip;
}
#endif
           //      BX_INFO (("stopped with %x", last_stop_reason));
                 buf[0] = 'S';
 /*                if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT ||
                     last_stop_reason == GDBSTUB_TRACE)
                   {
                      write_signal(&buf[1], SIGTRAP);
                   }
                 else
                   {
                      write_signal(&buf[1], 0);
                   }
                 put_reply(buf);
                 break;
   */           }
            
          case 's':
              {
                 char buf[255];
                 
             //    BX_INFO (("stepping"));
                 stub_trace_flag = 1;
          //       bx_cpu.cpu_loop(-1);
           //      DEV_vga_refresh();
                 stub_trace_flag = 0;
        //         BX_INFO (("stopped with %x", last_stop_reason));
                 buf[0] = 'S';
          //      if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT ||
             //        last_stop_reason == GDBSTUB_TRACE)
               //    {
                 //     write_signal(&buf[1], SIGTRAP);
                  // }
                // else
                //   {
                  //    write_signal(&buf[1], SIGTRAP);
                //   }
                 put_reply(buf);
                 break;
              }
            
          case 'M':
              {
                 int addr;
                 int len;
                 unsigned char mem[255];
                 char* ebuf;
                 
                 addr = strtoul(&buffer[1], &ebuf, 16);
                 len = strtoul(ebuf + 1, &ebuf, 16);
                 hex2mem(ebuf + 1, mem, len);

//BX_INFO(("write addr%8x\tlen %2x,content %8x",addr,len,*(unsigned int *)&mem[0]));
                 if (len == 4 && *(unsigned int *)&mem[0] == 0xef9f0001)
                   {
                      insert_breakpoint(addr);
                      put_reply("OK");
                   }
                 else if (remove_breakpoint(addr, len))
                   {
                      put_reply("OK");
                   }
                 else
                   {
  /*                    if (access_linear(addr,
                                        len,
                                        BX_WRITE,
                                        mem))
                        {
                           put_reply("OK");
                        }
                      else
                        {
                           put_reply("ENN");
                        }
    */               }
                 break;
              }
            
          case 'm':
              {
                 int addr;
                 int len;
                 char* ebuf;
                
                 addr = strtoul(&buffer[1], &ebuf, 16);
                 len = strtoul(ebuf + 1, NULL, 16);
	         printf("addr=%d\n",addr);
	         printf("len=%d\n",len);
            

/*
                 BX_INFO (("read addr %x len %x", addr, len));
                 
                 access_linear(addr,
                               len,
                               BX_READ,
                               mem);
*/
                 mem2hex((char *)mem, obuf, len);
   
                 put_reply(obuf);
                 break;
           }
          case 'P':
              {
                 int reg;
                 int value;
                 char* ebuf;
                 
                 reg = strtoul(&buffer[1], &ebuf, 16);
                 value = ntohl(strtoul(ebuf + 1, &ebuf, 16));
                 
             //    BX_INFO (("reg %d set to %x", reg, value));

//if (reg <=15) GPR(reg) = value;
#if 0
switch (reg)
{
case 1:
GPR(1) = value;
break;
case 2:
GPR(2) = value;
break;
case 3:
GPR(3) = value;
break;
case 4:
ESP = value;
break;
case 5:
EBP = value;
break;
case 6:
ESI = value;
break;
case 7:
EDI = value;
break;
case 8:
EIP = value;
break;
default:
break;
}
#endif
                 put_reply("OK");
                 
                 break;
              }
            
          case 'g':
{
            int i;
         //   for (i=0;i<15;i++) registers[i] = GPR(i);
   /*         if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT)
              {
                 registers[15] = GPR(15) + 4;
              }
            else
              {
                 registers[15] = GPR(15);
              } */
   //registers[17] = BX_CPU(0)->regs.regs_C.cpsr;
      //      mem2hex((char *)registers, obuf, NUMREGSBYTES);

            int regcounter=72;
	    char * ziel =obuf;
            while (regcounter>0)
               {
                sprintf(ziel,"00000000");
	
		 ziel=ziel+8;
                regcounter--;
                   };


            put_reply(obuf);
            break;
            }
          case '?':
            sprintf(obuf, "S%02x", SIGTRAP);
            put_reply(obuf);
            break;
            
          case 'H':
            if (buffer[1] == 'c')
              {
                 continue_thread = strtol(&buffer[2], NULL, 16);
                 put_reply("OK");
              }
            else if (buffer[1] == 'g')
              {
                 other_thread = strtol(&buffer[2], NULL, 16);
                 put_reply("OK");
              }
            else
              {
                 put_reply("ENN");
              }
            break;
            
          case 'q':
            if (buffer[1] == 'C')
              {
                 sprintf(obuf,"QC1");
                 put_reply(obuf);
              }
           else if (strncmp(&buffer[1], "Offsets", strlen("Offsets")) == 0)
              {
                 sprintf(obuf,"Text=0;Data=0;Bss=0");
                 put_reply(obuf);

              }
            else
              {
                 put_reply("ENN");
              }
            break;
            
          case 'k':
        //    BX_PANIC (("Debugger asked us to quit\n"));
            break;
            
          default:
            put_reply("");
            break;
         }
     }
}





static void server_connect(int portn)
{
   struct sockaddr_in sockaddr;
   socklen_t sockaddr_len;
   struct protoent *protoent;
   int r;
   int opt;
   
   listen_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
   if (listen_socket_fd == -1)
     {
       printf(("Failed to create socket\n"));
       exit(1);
     }
   
   /* Allow rapid reuse of this port */
   opt = 1;
   r = setsockopt(listen_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
   if (r == -1)
     {
  //     BX_INFO (("setsockopt(SO_REUSEADDR) failed\n"));
     }
   
   memset (&sockaddr, '\000', sizeof sockaddr);
#if BX_HAVE_SOCKADDR_IN_SIN_LEN
   // if you don't have sin_len change that to #if 0. This is the subject of
   // bug [ 626840 ] no 'sin_len' in 'struct sockaddr_in'.
   sockaddr.sin_len = sizeof sockaddr;
#endif
   sockaddr.sin_family = AF_INET;
   sockaddr.sin_port = htons(portn);
   sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

   r = bind(listen_socket_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
   if (r == -1)
     {
    printf (("Failed to bind socket\n"));
     }

   r = listen(listen_socket_fd, 0);
   if (r == -1)
     {
      printf(("Failed to listen on socket\n"));
     }
   
   sockaddr_len = sizeof sockaddr;
   socket_fd = accept(listen_socket_fd, (struct sockaddr *)&sockaddr, &sockaddr_len);
   if (socket_fd == -1)
     {
      printf (("Failed to accept on socket\n"));
     }
   close(listen_socket_fd);
   
   protoent = getprotobyname ("tcp");
   if (!protoent)
     {
     printf (("getprotobyname (\"tcp\") failed\n"));
       return ;
     }

   /* Disable Nagle - allow small packets to be sent without delay. */
   opt = 1;
   r = setsockopt (socket_fd, protoent->p_proto, TCP_NODELAY, &opt, sizeof(opt));
   if (r == -1)
     {
   printf (("setsockopt(TCP_NODELAY) failed\n"));
     }
    
}

//static 
int wait_for_connect(int portn)
{
//http://www.risc.jku.at/people/schreine/papers/rt++-linuxmag1/main.html	
      printf ("wait for connect\n");	 
   pthread_t thread1;
	  
  server_connect(portn);
  // server_connect(2013);
   printf("start debug loop\n");
   /* Do debugger command loop */
   
   pthread_create(&thread1, NULL, &debug_loop, NULL);
  // debug_loop();
	
	
	return 1;
}        
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


package gdb_pack is

  function wait_for_connect (portn : integer) return integer;
  attribute foreign of wait_for_connect :
    function is "VHPIDIRECT wait_for_connect";
  
  
end;

package body gdb_pack is

  function wait_for_connect (portn : integer) return integer is

  begin
    assert false report "VHPI" severity failure;
  end wait_for_connect;
  
  
  
end gdb_pack;
_______________________________________________
Ghdl-discuss mailing list
Ghdl-discuss@gna.org
https://mail.gna.org/listinfo/ghdl-discuss

Reply via email to