Wojciech M. Zabołotny
2018-05-24 12:42:04 UTC
Sometimes I need to run a VHDL simulation which communicates
with the C or Python application exchanging data other
than simple byte stream.
The minimal solution should provide exchange of at least
"packets" or "messages" of arbitrary length.
The sources below implement "VZMQ" that allows you
to send and receive such messages to/from the simulation
running in GHDL using the ZeroMQ library (so you can
communicate with application written in any language
that supports ZMQ).
The script "runme.sh" compiles the VZMQ, starts the
GHDL simulation and opens the xterm window, that
after a few seconds runs the Python script that
exchanges messages with the GHDL simulation.
The example messages are just strings, but you may
also transmit more complex structures (However,
the ZMQ should access them as the array of bytes
and VHDL should access them as the std_logic_vector.
You need to provide the necessary
serialization/deserialization procedures.
The code is published as PUBLIC DOMAIN or under
Creative Commons CC0 license (whichever better suits
your needs).
I do not give any warranty. You use it at your own
risk.
Wojciech M. Zabolotny (wzab01<at>gmail.com)
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh26462
# Made on 2018-05-24 14:25 CEST by <***@wzdell>.
# Source directory was '/tmp/zmq'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 172 -rwxr--r-- runme.sh
# 2334 -rw-r--r-- vzmqc.c
# 2644 -rw-r--r-- vzmq_pkg.vhd
# 3506 -rw-r--r-- vzmq_tb.vhd
# 258 -rw-r--r-- zmqtest.py
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= runme.sh ==============
if test -n "${keep_file}" && test -f 'runme.sh'
then
${echo} "x - SKIPPING runme.sh (file already exists)"
else
${echo} "x - extracting runme.sh (text)"
sed 's/^X//' << 'SHAR_EOF' > 'runme.sh' &&
#!/bin/sh
set -e
gcc -c vzmqc.c
ghdl -a vzmq_pkg.vhd vzmq_tb.vhd
ghdl -e -Wl,vzmqc.o -Wl,-lzmq vzmq_tb
xterm -e "sleep 5; python zmqtest.py" &
X./vzmq_tb --wave=test.ghw
X
SHAR_EOF
(set 20 18 05 24 12 31 45 'runme.sh'
eval "${shar_touch}") && \
chmod 0744 'runme.sh'
if test $? -ne 0
then ${echo} "restore of runme.sh failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'runme.sh': 'MD5 check failed'
) << \SHAR_EOF
71803dba096f59d026e27a5ac789379b runme.sh
SHAR_EOF
else
test `LC_ALL=C wc -c < 'runme.sh'` -ne 172 && \
${echo} "restoration warning: size of 'runme.sh' is not 172"
fi
fi
# ============= vzmqc.c ==============
if test -n "${keep_file}" && test -f 'vzmqc.c'
then
${echo} "x - SKIPPING vzmqc.c (file already exists)"
else
${echo} "x - extracting vzmqc.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'vzmqc.c' &&
/*
This is the C part of the VZMQ - package allowing to pass ZMQ messages
from software to the GHDL simuulation.
Code written by Wojciech M. Zabolotny (wzab01<at>gmail.com or
wzab<at>ise.pw.edu.pl)
Published as PUBLIC DOMAIN or under Creative Commons CC0 license
X */
X
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <zmq.h>
X
int zmq_smax=0, zmq_rmax=0;
void *ctx = NULL;
unsigned int mprio;
void *socket = NULL;
int rc=-1;
X
void init_zmq_server_c(const int i_zmq_smax,const int i_zmq_rmax)
{
X zmq_smax = i_zmq_smax;
X zmq_rmax = i_zmq_rmax;
X ctx = zmq_ctx_new ();
X assert (ctx);
X /* Create ZMQ_STREAM socket */
X socket = zmq_socket (ctx, ZMQ_PAIR); //When it was ZMQ_REP, I couldn't repeat call
X assert (socket);
X rc = zmq_bind (socket, "ipc://mystream2");
X assert (rc == 0);
}
X
void close_zmq_server(int ile)
{
}
X
void zmq_get_message_c(int nmax,int * nact,unsigned char *buf)
{
X int msize;
X unsigned char rbuf[zmq_rmax];
X if(nmax > zmq_rmax) {
X fprintf(stderr,"Too many bytes requested %d>%d\n",nmax,zmq_rmax);
X *nact=-1;
X return;
X }
X msize = zmq_recv (socket,rbuf,nmax, ZMQ_DONTWAIT);
X if(msize<0) {
X if(errno==EAGAIN) {
X *nact = 0;
X return;
X }
X perror("receive error ");
X fprintf(stderr,"Can't receive %d\n",msize);
X *nact=msize;
X return;
X } else {
X fprintf(stderr,"Received message of length: %d\n",msize);
X int i,j;
X for(i=0;i<msize;i++) {
X fprintf(stderr,"%c",rbuf[i]);
X for(j=0;j<8;j++)
X if(rbuf[i] & (1<<j))
X buf[i*8+j]=3;
X else
X buf[i*8+j]=2;
X }
X fprintf(stderr,"\n");
X *nact=msize;
X return;
X }
}
X
void zmq_put_message_c(int msize,int * nact,unsigned char *buf)
{
X int res=0,i,j;
X unsigned char wbuf[zmq_smax];
X //Check if the number of transmitted bytes is correct
X if(msize > zmq_smax) {
X fprintf(stderr,"Too many bytes requested %d>%d\n",msize,zmq_smax);
X *nact=-1;
X return;
X }
X //Translate the message from bit vector to bytes
X for(i=0;i<msize;i++) {
X wbuf[i] = 0;
X for(j=0;j<8;j++)
X if(buf[8*i+j]==3)
X wbuf[i] |= (1<<j);
X }
X res = zmq_send(socket,wbuf,msize, 0);
X if(res<0) {
X perror("transmit error ");
X fprintf(stderr,"Can't receive %d\n",res);
X *nact=res;
X return;
X } else {
X *nact=res;
X return;
X }
}
X
X
SHAR_EOF
(set 20 18 05 24 14 21 21 'vzmqc.c'
eval "${shar_touch}") && \
chmod 0644 'vzmqc.c'
if test $? -ne 0
then ${echo} "restore of vzmqc.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'vzmqc.c': 'MD5 check failed'
) << \SHAR_EOF
87bdd7492c372795944845a7b5c5f0f1 vzmqc.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'vzmqc.c'` -ne 2334 && \
${echo} "restoration warning: size of 'vzmqc.c' is not 2334"
fi
fi
# ============= vzmq_pkg.vhd ==============
if test -n "${keep_file}" && test -f 'vzmq_pkg.vhd'
then
${echo} "x - SKIPPING vzmq_pkg.vhd (file already exists)"
else
${echo} "x - extracting vzmq_pkg.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'vzmq_pkg.vhd' &&
-------------------------------------------------------------------------------
-- Title : Package vzmq
-- Project :
-------------------------------------------------------------------------------
-- File : vzmq_tb.vhd
-- Author : Wojciech M. Zabolotny (wzab01<at>gmail.com or wzab<at>ise.pw.edu.pl
-- Company : Institute of Electronic Systems
-- License : Public Domain or Creative Commons CC0
-- Created : 2018-05-20
-- Last update: 2018-05-24
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: vzmq - package for passing ZMQ messages to GHDL simulation
-------------------------------------------------------------------------------
-- Copyright (c) 2016,2018
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2018-05-20 1.0 wzab Created
-------------------------------------------------------------------------------
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
X
package vzmq is
X
X -- Maximum length of received and transmitted messages in bytes
X constant ZMQ_RCV_MAX : integer := 1000;
X constant ZMQ_SND_MAX : integer := 2000;
X
X procedure init_zmq_server (
X constant max_send : in integer;
X constant max_receive : in integer
X );
X attribute foreign of init_zmq_server : procedure is "VHPIDIRECT init_zmq_server_c";
X
X procedure zmq_get_message (
X variable nmax : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_RCV_MAX-1)
X );
X attribute foreign of zmq_get_message : procedure is "VHPIDIRECT zmq_get_message_c";
X
X procedure zmq_put_message (
X variable msize : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_SND_MAX-1)
X );
X attribute foreign of zmq_put_message : procedure is "VHPIDIRECT zmq_put_message_c";
X
end vzmq;
X
package body vzmq is
X
X procedure init_zmq_server (
X constant max_send : in integer;
X constant max_receive : in integer
X ) is
X begin
X assert false severity failure;
X end init_zmq_server;
X
X procedure zmq_get_message (
X variable nmax : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_RCV_MAX-1)
X ) is
X begin
X assert false severity failure;
X end zmq_get_message;
X
X procedure zmq_put_message (
X variable msize : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_SND_MAX-1)
X ) is
X begin
X assert false severity failure;
X end zmq_put_message;
X
end vzmq;
X
SHAR_EOF
(set 20 18 05 24 12 52 03 'vzmq_pkg.vhd'
eval "${shar_touch}") && \
chmod 0644 'vzmq_pkg.vhd'
if test $? -ne 0
then ${echo} "restore of vzmq_pkg.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'vzmq_pkg.vhd': 'MD5 check failed'
) << \SHAR_EOF
8d847724053e567b333ba1c5ac85c8ca vzmq_pkg.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'vzmq_pkg.vhd'` -ne 2644 && \
${echo} "restoration warning: size of 'vzmq_pkg.vhd' is not 2644"
fi
fi
# ============= vzmq_tb.vhd ==============
if test -n "${keep_file}" && test -f 'vzmq_tb.vhd'
then
${echo} "x - SKIPPING vzmq_tb.vhd (file already exists)"
else
${echo} "x - extracting vzmq_tb.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'vzmq_tb.vhd' &&
-------------------------------------------------------------------------------
-- Title : Testbench for vzmq
-- Project :
-------------------------------------------------------------------------------
-- File : vhpi_tb.vhd
-- Author : Wojciech M. Zabolotny (wzab01<at>gmail.com or wzab<at>ise.pw.edu.pl
-- Company : Institute of Electronic Systems
-- License : Public Domain or Creative Commons CC0
-- Created : 2018-05-20
-- Last update: 2018-05-24
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: vzmq - package for passing ZMQ messages to GHDL simulation
-------------------------------------------------------------------------------
-- Copyright (c) 2016, 2018
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2018-05-20 1.0 wzab Created
-------------------------------------------------------------------------------
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library work;
use work.vzmq.all;
-------------------------------------------------------------------------------
X
entity vzmq_tb is
X
end vzmq_tb;
X
-------------------------------------------------------------------------------
X
architecture symul2 of vzmq_tb is
X
X signal sco : integer := 13254;
X signal sflag : std_logic := '0';
X
begin -- symul2
X
X process
X variable ts : integer := 5;
X variable nmax : integer := 1000;
X variable nact : integer := 0;
X variable buf : unsigned(0 to 8*ZMQ_RCV_MAX-1) := (others => '0');
X variable j : integer := 0;
X variable c : integer := 0;
X variable ln : line;
X begin
X init_zmq_server(ZMQ_SND_MAX, ZMQ_RCV_MAX);
X while true loop
X zmq_get_message(nmax, nact, buf);
X j := 0;
X c := 0;
X if nact > 0 then
X write(ln, integer'image(nact));
X writeline(OUTPUT, ln);
X for i in 0 to (8*nact)-1 loop
X c := c/2;
X if buf(i) = '1' then
X c :=c+128;
X end if;
X if j = 7 then
X write(ln, character'val(c));
X j := 0;
X c := 0;
X else
X j :=j+1;
X end if;
X end loop; -- i
X writeline(OUTPUT, ln);
X sflag <= '1';
X wait for 5 ns;
X sflag <= '0';
X wait for 5 ns;
X end if;
X end loop;
X
X end process;
X
X process(sflag)
X variable sbuf : unsigned(0 to 8*ZMQ_SND_MAX-1) := (others => '0');
X constant txt : string := "Confirmation message";
X variable cd : unsigned(7 downto 0);
X variable res : integer := 0;
X variable mlen : integer := 0;
X begin
X if rising_edge(sflag) then
X sbuf := (others => '0');
X for i in 1 to txt'length loop
X cd := to_unsigned(character'pos(txt(i)), 8);
X for j in 0 to 7 loop
X if cd(j) = '1' then
X sbuf((i-1)*8+j) := '1';
X end if;
X end loop; -- j
X end loop; -- i
X mlen := txt'length;
X report "message sent!" severity note;
X zmq_put_message(mlen, res, sbuf);
X report "returned " & integer'image(res) severity note;
X null;
X end if;
X null;
X end process;
X
end symul2;
X
-------------------------------------------------------------------------------
SHAR_EOF
(set 20 18 05 24 14 21 43 'vzmq_tb.vhd'
eval "${shar_touch}") && \
chmod 0644 'vzmq_tb.vhd'
if test $? -ne 0
then ${echo} "restore of vzmq_tb.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'vzmq_tb.vhd': 'MD5 check failed'
) << \SHAR_EOF
b6748f1d917c60d56de015a8acd90632 vzmq_tb.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'vzmq_tb.vhd'` -ne 3506 && \
${echo} "restoration warning: size of 'vzmq_tb.vhd' is not 3506"
fi
fi
# ============= zmqtest.py ==============
if test -n "${keep_file}" && test -f 'zmqtest.py'
then
${echo} "x - SKIPPING zmqtest.py (file already exists)"
else
${echo} "x - extracting zmqtest.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'zmqtest.py' &&
#!/usr/bin/python
import zmq
import struct
ctx=zmq.Context()
s=ctx.socket(zmq.PAIR)
s.connect("ipc://mystream2")
mg1="This is the 1st message!"
s.send(mg1)
mg1="The 2nd message"
s.send(mg1)
mg1="The 3rd one"
s.send(mg1)
while True:
X m=s.recv()
X print m
X
X
X
SHAR_EOF
(set 20 18 05 24 12 12 13 'zmqtest.py'
eval "${shar_touch}") && \
chmod 0644 'zmqtest.py'
if test $? -ne 0
then ${echo} "restore of zmqtest.py failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'zmqtest.py': 'MD5 check failed'
) << \SHAR_EOF
021cab96589714a365381c9b2483fd43 zmqtest.py
SHAR_EOF
else
test `LC_ALL=C wc -c < 'zmqtest.py'` -ne 258 && \
${echo} "restoration warning: size of 'zmqtest.py' is not 258"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0
with the C or Python application exchanging data other
than simple byte stream.
The minimal solution should provide exchange of at least
"packets" or "messages" of arbitrary length.
The sources below implement "VZMQ" that allows you
to send and receive such messages to/from the simulation
running in GHDL using the ZeroMQ library (so you can
communicate with application written in any language
that supports ZMQ).
The script "runme.sh" compiles the VZMQ, starts the
GHDL simulation and opens the xterm window, that
after a few seconds runs the Python script that
exchanges messages with the GHDL simulation.
The example messages are just strings, but you may
also transmit more complex structures (However,
the ZMQ should access them as the array of bytes
and VHDL should access them as the std_logic_vector.
You need to provide the necessary
serialization/deserialization procedures.
The code is published as PUBLIC DOMAIN or under
Creative Commons CC0 license (whichever better suits
your needs).
I do not give any warranty. You use it at your own
risk.
Wojciech M. Zabolotny (wzab01<at>gmail.com)
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh26462
# Made on 2018-05-24 14:25 CEST by <***@wzdell>.
# Source directory was '/tmp/zmq'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 172 -rwxr--r-- runme.sh
# 2334 -rw-r--r-- vzmqc.c
# 2644 -rw-r--r-- vzmq_pkg.vhd
# 3506 -rw-r--r-- vzmq_tb.vhd
# 258 -rw-r--r-- zmqtest.py
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= runme.sh ==============
if test -n "${keep_file}" && test -f 'runme.sh'
then
${echo} "x - SKIPPING runme.sh (file already exists)"
else
${echo} "x - extracting runme.sh (text)"
sed 's/^X//' << 'SHAR_EOF' > 'runme.sh' &&
#!/bin/sh
set -e
gcc -c vzmqc.c
ghdl -a vzmq_pkg.vhd vzmq_tb.vhd
ghdl -e -Wl,vzmqc.o -Wl,-lzmq vzmq_tb
xterm -e "sleep 5; python zmqtest.py" &
X./vzmq_tb --wave=test.ghw
X
SHAR_EOF
(set 20 18 05 24 12 31 45 'runme.sh'
eval "${shar_touch}") && \
chmod 0744 'runme.sh'
if test $? -ne 0
then ${echo} "restore of runme.sh failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'runme.sh': 'MD5 check failed'
) << \SHAR_EOF
71803dba096f59d026e27a5ac789379b runme.sh
SHAR_EOF
else
test `LC_ALL=C wc -c < 'runme.sh'` -ne 172 && \
${echo} "restoration warning: size of 'runme.sh' is not 172"
fi
fi
# ============= vzmqc.c ==============
if test -n "${keep_file}" && test -f 'vzmqc.c'
then
${echo} "x - SKIPPING vzmqc.c (file already exists)"
else
${echo} "x - extracting vzmqc.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'vzmqc.c' &&
/*
This is the C part of the VZMQ - package allowing to pass ZMQ messages
from software to the GHDL simuulation.
Code written by Wojciech M. Zabolotny (wzab01<at>gmail.com or
wzab<at>ise.pw.edu.pl)
Published as PUBLIC DOMAIN or under Creative Commons CC0 license
X */
X
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <zmq.h>
X
int zmq_smax=0, zmq_rmax=0;
void *ctx = NULL;
unsigned int mprio;
void *socket = NULL;
int rc=-1;
X
void init_zmq_server_c(const int i_zmq_smax,const int i_zmq_rmax)
{
X zmq_smax = i_zmq_smax;
X zmq_rmax = i_zmq_rmax;
X ctx = zmq_ctx_new ();
X assert (ctx);
X /* Create ZMQ_STREAM socket */
X socket = zmq_socket (ctx, ZMQ_PAIR); //When it was ZMQ_REP, I couldn't repeat call
X assert (socket);
X rc = zmq_bind (socket, "ipc://mystream2");
X assert (rc == 0);
}
X
void close_zmq_server(int ile)
{
}
X
void zmq_get_message_c(int nmax,int * nact,unsigned char *buf)
{
X int msize;
X unsigned char rbuf[zmq_rmax];
X if(nmax > zmq_rmax) {
X fprintf(stderr,"Too many bytes requested %d>%d\n",nmax,zmq_rmax);
X *nact=-1;
X return;
X }
X msize = zmq_recv (socket,rbuf,nmax, ZMQ_DONTWAIT);
X if(msize<0) {
X if(errno==EAGAIN) {
X *nact = 0;
X return;
X }
X perror("receive error ");
X fprintf(stderr,"Can't receive %d\n",msize);
X *nact=msize;
X return;
X } else {
X fprintf(stderr,"Received message of length: %d\n",msize);
X int i,j;
X for(i=0;i<msize;i++) {
X fprintf(stderr,"%c",rbuf[i]);
X for(j=0;j<8;j++)
X if(rbuf[i] & (1<<j))
X buf[i*8+j]=3;
X else
X buf[i*8+j]=2;
X }
X fprintf(stderr,"\n");
X *nact=msize;
X return;
X }
}
X
void zmq_put_message_c(int msize,int * nact,unsigned char *buf)
{
X int res=0,i,j;
X unsigned char wbuf[zmq_smax];
X //Check if the number of transmitted bytes is correct
X if(msize > zmq_smax) {
X fprintf(stderr,"Too many bytes requested %d>%d\n",msize,zmq_smax);
X *nact=-1;
X return;
X }
X //Translate the message from bit vector to bytes
X for(i=0;i<msize;i++) {
X wbuf[i] = 0;
X for(j=0;j<8;j++)
X if(buf[8*i+j]==3)
X wbuf[i] |= (1<<j);
X }
X res = zmq_send(socket,wbuf,msize, 0);
X if(res<0) {
X perror("transmit error ");
X fprintf(stderr,"Can't receive %d\n",res);
X *nact=res;
X return;
X } else {
X *nact=res;
X return;
X }
}
X
X
SHAR_EOF
(set 20 18 05 24 14 21 21 'vzmqc.c'
eval "${shar_touch}") && \
chmod 0644 'vzmqc.c'
if test $? -ne 0
then ${echo} "restore of vzmqc.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'vzmqc.c': 'MD5 check failed'
) << \SHAR_EOF
87bdd7492c372795944845a7b5c5f0f1 vzmqc.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'vzmqc.c'` -ne 2334 && \
${echo} "restoration warning: size of 'vzmqc.c' is not 2334"
fi
fi
# ============= vzmq_pkg.vhd ==============
if test -n "${keep_file}" && test -f 'vzmq_pkg.vhd'
then
${echo} "x - SKIPPING vzmq_pkg.vhd (file already exists)"
else
${echo} "x - extracting vzmq_pkg.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'vzmq_pkg.vhd' &&
-------------------------------------------------------------------------------
-- Title : Package vzmq
-- Project :
-------------------------------------------------------------------------------
-- File : vzmq_tb.vhd
-- Author : Wojciech M. Zabolotny (wzab01<at>gmail.com or wzab<at>ise.pw.edu.pl
-- Company : Institute of Electronic Systems
-- License : Public Domain or Creative Commons CC0
-- Created : 2018-05-20
-- Last update: 2018-05-24
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: vzmq - package for passing ZMQ messages to GHDL simulation
-------------------------------------------------------------------------------
-- Copyright (c) 2016,2018
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2018-05-20 1.0 wzab Created
-------------------------------------------------------------------------------
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
X
package vzmq is
X
X -- Maximum length of received and transmitted messages in bytes
X constant ZMQ_RCV_MAX : integer := 1000;
X constant ZMQ_SND_MAX : integer := 2000;
X
X procedure init_zmq_server (
X constant max_send : in integer;
X constant max_receive : in integer
X );
X attribute foreign of init_zmq_server : procedure is "VHPIDIRECT init_zmq_server_c";
X
X procedure zmq_get_message (
X variable nmax : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_RCV_MAX-1)
X );
X attribute foreign of zmq_get_message : procedure is "VHPIDIRECT zmq_get_message_c";
X
X procedure zmq_put_message (
X variable msize : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_SND_MAX-1)
X );
X attribute foreign of zmq_put_message : procedure is "VHPIDIRECT zmq_put_message_c";
X
end vzmq;
X
package body vzmq is
X
X procedure init_zmq_server (
X constant max_send : in integer;
X constant max_receive : in integer
X ) is
X begin
X assert false severity failure;
X end init_zmq_server;
X
X procedure zmq_get_message (
X variable nmax : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_RCV_MAX-1)
X ) is
X begin
X assert false severity failure;
X end zmq_get_message;
X
X procedure zmq_put_message (
X variable msize : in integer;
X variable nact : out integer;
X variable v1 : inout unsigned(0 to 8*ZMQ_SND_MAX-1)
X ) is
X begin
X assert false severity failure;
X end zmq_put_message;
X
end vzmq;
X
SHAR_EOF
(set 20 18 05 24 12 52 03 'vzmq_pkg.vhd'
eval "${shar_touch}") && \
chmod 0644 'vzmq_pkg.vhd'
if test $? -ne 0
then ${echo} "restore of vzmq_pkg.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'vzmq_pkg.vhd': 'MD5 check failed'
) << \SHAR_EOF
8d847724053e567b333ba1c5ac85c8ca vzmq_pkg.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'vzmq_pkg.vhd'` -ne 2644 && \
${echo} "restoration warning: size of 'vzmq_pkg.vhd' is not 2644"
fi
fi
# ============= vzmq_tb.vhd ==============
if test -n "${keep_file}" && test -f 'vzmq_tb.vhd'
then
${echo} "x - SKIPPING vzmq_tb.vhd (file already exists)"
else
${echo} "x - extracting vzmq_tb.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'vzmq_tb.vhd' &&
-------------------------------------------------------------------------------
-- Title : Testbench for vzmq
-- Project :
-------------------------------------------------------------------------------
-- File : vhpi_tb.vhd
-- Author : Wojciech M. Zabolotny (wzab01<at>gmail.com or wzab<at>ise.pw.edu.pl
-- Company : Institute of Electronic Systems
-- License : Public Domain or Creative Commons CC0
-- Created : 2018-05-20
-- Last update: 2018-05-24
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: vzmq - package for passing ZMQ messages to GHDL simulation
-------------------------------------------------------------------------------
-- Copyright (c) 2016, 2018
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2018-05-20 1.0 wzab Created
-------------------------------------------------------------------------------
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library work;
use work.vzmq.all;
-------------------------------------------------------------------------------
X
entity vzmq_tb is
X
end vzmq_tb;
X
-------------------------------------------------------------------------------
X
architecture symul2 of vzmq_tb is
X
X signal sco : integer := 13254;
X signal sflag : std_logic := '0';
X
begin -- symul2
X
X process
X variable ts : integer := 5;
X variable nmax : integer := 1000;
X variable nact : integer := 0;
X variable buf : unsigned(0 to 8*ZMQ_RCV_MAX-1) := (others => '0');
X variable j : integer := 0;
X variable c : integer := 0;
X variable ln : line;
X begin
X init_zmq_server(ZMQ_SND_MAX, ZMQ_RCV_MAX);
X while true loop
X zmq_get_message(nmax, nact, buf);
X j := 0;
X c := 0;
X if nact > 0 then
X write(ln, integer'image(nact));
X writeline(OUTPUT, ln);
X for i in 0 to (8*nact)-1 loop
X c := c/2;
X if buf(i) = '1' then
X c :=c+128;
X end if;
X if j = 7 then
X write(ln, character'val(c));
X j := 0;
X c := 0;
X else
X j :=j+1;
X end if;
X end loop; -- i
X writeline(OUTPUT, ln);
X sflag <= '1';
X wait for 5 ns;
X sflag <= '0';
X wait for 5 ns;
X end if;
X end loop;
X
X end process;
X
X process(sflag)
X variable sbuf : unsigned(0 to 8*ZMQ_SND_MAX-1) := (others => '0');
X constant txt : string := "Confirmation message";
X variable cd : unsigned(7 downto 0);
X variable res : integer := 0;
X variable mlen : integer := 0;
X begin
X if rising_edge(sflag) then
X sbuf := (others => '0');
X for i in 1 to txt'length loop
X cd := to_unsigned(character'pos(txt(i)), 8);
X for j in 0 to 7 loop
X if cd(j) = '1' then
X sbuf((i-1)*8+j) := '1';
X end if;
X end loop; -- j
X end loop; -- i
X mlen := txt'length;
X report "message sent!" severity note;
X zmq_put_message(mlen, res, sbuf);
X report "returned " & integer'image(res) severity note;
X null;
X end if;
X null;
X end process;
X
end symul2;
X
-------------------------------------------------------------------------------
SHAR_EOF
(set 20 18 05 24 14 21 43 'vzmq_tb.vhd'
eval "${shar_touch}") && \
chmod 0644 'vzmq_tb.vhd'
if test $? -ne 0
then ${echo} "restore of vzmq_tb.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'vzmq_tb.vhd': 'MD5 check failed'
) << \SHAR_EOF
b6748f1d917c60d56de015a8acd90632 vzmq_tb.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'vzmq_tb.vhd'` -ne 3506 && \
${echo} "restoration warning: size of 'vzmq_tb.vhd' is not 3506"
fi
fi
# ============= zmqtest.py ==============
if test -n "${keep_file}" && test -f 'zmqtest.py'
then
${echo} "x - SKIPPING zmqtest.py (file already exists)"
else
${echo} "x - extracting zmqtest.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'zmqtest.py' &&
#!/usr/bin/python
import zmq
import struct
ctx=zmq.Context()
s=ctx.socket(zmq.PAIR)
s.connect("ipc://mystream2")
mg1="This is the 1st message!"
s.send(mg1)
mg1="The 2nd message"
s.send(mg1)
mg1="The 3rd one"
s.send(mg1)
while True:
X m=s.recv()
X print m
X
X
X
SHAR_EOF
(set 20 18 05 24 12 12 13 'zmqtest.py'
eval "${shar_touch}") && \
chmod 0644 'zmqtest.py'
if test $? -ne 0
then ${echo} "restore of zmqtest.py failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'zmqtest.py': 'MD5 check failed'
) << \SHAR_EOF
021cab96589714a365381c9b2483fd43 zmqtest.py
SHAR_EOF
else
test `LC_ALL=C wc -c < 'zmqtest.py'` -ne 258 && \
${echo} "restoration warning: size of 'zmqtest.py' is not 258"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0