Skip to content

Commit 36d63f1

Browse files
committed
add cosim utils to VUnit, use it in examples/vhdl/external_buffer
1 parent 4bffc3c commit 36d63f1

2 files changed

Lines changed: 145 additions & 0 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
# You can obtain one at http://mozilla.org/MPL/2.0/.
4+
#
5+
# Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com
6+
7+
8+
from vunit.cosim import *
9+
import ctypes
10+
from os.path import join, dirname, isfile
11+
12+
13+
args = [line.rstrip('\n') for line in open(join(dirname(__file__), 'args.txt'))]
14+
15+
xargs = enc_args(args)
16+
17+
print("\nREGULAR EXECUTION")
18+
ghdl = dlopen(args[0])
19+
try:
20+
ghdl.main(len(xargs)-1, xargs)
21+
# FIXME With VHDL 93, the execution is Aborted and Python exits here
22+
except SystemExit as exc:
23+
if exc.code is not 0:
24+
exit(exc.code)
25+
dlclose(ghdl)
26+
27+
print("\nPYTHON ALLOCATION")
28+
ghdl = dlopen(args[0])
29+
30+
data = [111, 122, 133, 144, 155]
31+
32+
buf = byte_buf(data + [0 for x in range(2*len(data))])
33+
34+
ghdl.set_string_ptr(0, buf)
35+
36+
for i, v in enumerate(read_byte_buf(buf)):
37+
print("py " + str(i) + ": " + str(v))
38+
39+
ghdl.ghdl_main(len(xargs)-1, xargs)
40+
41+
for i, v in enumerate(read_byte_buf(buf)):
42+
print("py " + str(i) + ": " + str(v))
43+
44+
dlclose(ghdl)

vunit/cosim.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
# You can obtain one at http://mozilla.org/MPL/2.0/.
4+
#
5+
# Copyright (c) 2014-2019, Lars Asplund lars.anders.asplund@gmail.com
6+
7+
"""
8+
Utils for co-execution of a dynamically loadable binaries or shared libraries
9+
"""
10+
11+
from __future__ import print_function
12+
import ctypes
13+
import _ctypes
14+
from sys import platform
15+
from os.path import isfile
16+
17+
18+
def dlopen(path):
19+
"""
20+
Open/load a PIE binary or a shared library.
21+
"""
22+
if not isfile(path):
23+
print('Executable binary not found: ' + path)
24+
exit(1)
25+
try:
26+
return ctypes.CDLL(path)
27+
except OSError:
28+
print('Loading executables dynamically seems not to be supported on this platform')
29+
exit(1)
30+
31+
32+
def dlclose(obj):
33+
"""
34+
Close/unload a PIE binary or a shared library.
35+
36+
:param obj: object returned by ctypes.CDLL when the resource was loaded
37+
"""
38+
if platform == 'linux':
39+
_ctypes.dlclose(obj._handle) # pylint:disable=protected-access
40+
# else:
41+
# _ctypes.FreeLibrary(obj._handle) # pylint:disable=protected-access
42+
43+
44+
def enc_args(args):
45+
"""
46+
Convert args to a suitable format for a foreign C function.
47+
48+
:param args: list of strings
49+
"""
50+
xargs = (ctypes.POINTER(ctypes.c_char) * len(args))()
51+
for idx, arg in enumerate(args):
52+
xargs[idx] = ctypes.create_string_buffer(arg.encode('utf-8'))
53+
return xargs
54+
55+
56+
def byte_buf(lst):
57+
"""
58+
Convert array to a string buffer (uint8_t* in C).
59+
60+
:param lst: list of naturals range [0,255]
61+
"""
62+
return ctypes.create_string_buffer(bytes(lst), len(lst))
63+
64+
65+
def int_buf(lst, bpw=4, signed=True):
66+
"""
67+
Convert array to a string buffer (uint8_t* in C).
68+
69+
:param lst: list of integers
70+
:param bpw: number of bytes per word/integer
71+
:param signed: whether to encode the numbers as signed
72+
"""
73+
out = [None] * 4 * len(lst)
74+
for idx, val in enumerate(lst):
75+
out[idx * 4:idx * 4 + 4] = (val).to_bytes(bpw, byteorder="little", signed=signed)
76+
return byte_buf(out)
77+
78+
79+
def read_byte_buf(buf):
80+
"""
81+
Read byte/string buffer (uint8_t* in C) as a list of numbers.
82+
"""
83+
return read_int_buf(buf, bpw=1, signed=False)
84+
85+
86+
def read_int_buf(buf, bpw=4, signed=True):
87+
"""
88+
Read byte/string buffer as a list of numbers.
89+
90+
:param buf: byte/string buffer (uint8_t* in C) to read from
91+
:param bpw: number of bytes per word/integer
92+
:param signed: whether to decode the numbers as signed
93+
"""
94+
out = [None] * int(len(buf) / bpw)
95+
if bpw == 1:
96+
for idx, val in enumerate(buf):
97+
out[idx] = int.from_bytes(val, byteorder="little", signed=signed)
98+
else:
99+
for idx, _ in enumerate(out):
100+
out[idx] = int.from_bytes(buf[idx * bpw:idx * bpw + bpw], byteorder="little", signed=signed)
101+
return out

0 commit comments

Comments
 (0)