Skip to content

Commit 2e6fb01

Browse files
committed
add(examples/vhdl/external_buffer)
1 parent 9c41505 commit 2e6fb01

6 files changed

Lines changed: 270 additions & 5 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
External Buffer
9+
---------------
10+
11+
`Interfacing with foreign languages (C) through VHPIDIRECT <https://ghdl.readthedocs.io/en/latest/using/Foreign.html>`_
12+
13+
An array of type ``uint8_t`` is allocated in a C application and some values
14+
are written to the first ``1/3`` positions. Then, the VHDL simulation is
15+
executed, where the (external) array/buffer is used.
16+
17+
In the VHDL testbenches, two vector pointers are created, each of them using
18+
a different access mechanism (``extfunc`` or ``extacc``). One of them is used to copy
19+
the first ``1/3`` elements to positions ``[1/3, 2/3)``, while incrementing each value
20+
by one. The second one is used to copy elements from ``[1/3, 2/3)`` to ``[2/3, 3/3)``,
21+
while incrementing each value by two.
22+
23+
When the simulation is finished, the C application checks whether data was successfully
24+
copied/modified. The content of the buffer is printed both before and after the
25+
simulation.
26+
"""
27+
28+
from vunit import VUnit
29+
from os import popen
30+
from os.path import join, dirname
31+
32+
src_path = join(dirname(__file__), 'src')
33+
34+
c_obj = join(src_path, 'main.o')
35+
# Compile C application to an object
36+
print(popen(' '.join([
37+
'gcc', '-fPIC',
38+
'-c', join(src_path, 'main.c'),
39+
'-o', c_obj
40+
])).read())
41+
42+
# Enable the external feature for strings
43+
vu = VUnit.from_argv(vhdl_standard='2008', compile_builtins=False)
44+
vu.add_builtins({'string': True})
45+
46+
lib = vu.add_library('lib')
47+
lib.add_source_files(join(src_path, '*.vhd'))
48+
49+
# Add the C object to the elaboration of GHDL
50+
vu.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj])
51+
52+
vu.main()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
External Buffer
3+
4+
Interfacing with foreign languages (C) through VHPIDIRECT:
5+
https://ghdl.readthedocs.io/en/latest/using/Foreign.html
6+
7+
An array of type uint8_t is allocated and some values are written to the first 1/3
8+
positions. Then, the VHDL simulation is executed, where the (external) array/buffer
9+
is used. When the simulation is finished, the results are checked. The content of
10+
the buffer is printed both before and after the simulation.
11+
12+
NOTE: This file is expected to be used along with tb_ext_byte_vector.vhd or tb_ext_string.vhd
13+
*/
14+
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
#include <stdint.h>
18+
19+
extern int ghdl_main (int argc, char **argv);
20+
21+
uint8_t *D[1];
22+
const uint32_t length = 5;
23+
24+
// Check procedure, to be executed when GHDL exits.
25+
// The simulation is expected to copy the first 1/3 elements to positions [1/3, 2/3),
26+
// while incrementing each value by one, and then copy elements from [1/3, 2/3) to
27+
// [2/3, 3/3), while incrementing each value by two.
28+
static void exit_handler(void) {
29+
int i, j, z, k;
30+
uint8_t expected, got;
31+
k = 0;
32+
for (j=0; j<3; j++) {
33+
k += j;
34+
for(i=0; i<length; i++) {
35+
z = (length*j)+i;
36+
37+
expected = (i+1)*11 + k;
38+
got = D[0][z];
39+
if (expected != got) {
40+
printf("check error %d: %d %d\n", z, expected, got);
41+
exit(1);
42+
}
43+
printf("%d: %d\n", z, got);
44+
}
45+
}
46+
free(D[0]);
47+
}
48+
49+
// Main entrypoint of the application
50+
int main(int argc, char **argv) {
51+
// Allocate a buffer which is three times the number of values
52+
// that we want to copy/modify
53+
D[0] = (uint8_t *) malloc(3*length*sizeof(uint8_t));
54+
if ( D[0] == NULL ) {
55+
perror("execution of malloc() failed!\n");
56+
return -1;
57+
}
58+
// Initialize the first 1/3 of the buffer
59+
int i;
60+
for(i=0; i<length; i++) {
61+
D[0][i] = (i+1)*11;
62+
}
63+
// Print all the buffer
64+
for(i=0; i<3*length; i++) {
65+
printf("%d: %d\n", i, D[0][i]);
66+
}
67+
68+
// Register a function to be called when GHDL exits
69+
atexit(exit_handler);
70+
71+
// Start the simulation
72+
return ghdl_main(argc, argv);
73+
}
74+
75+
// External through access (mode = extacc)
76+
77+
void set_string_ptr(uint8_t id, uint8_t *p) {
78+
//printf("C set_string_ptr(%d, %p)\n", id, p);
79+
D[id] = p;
80+
}
81+
82+
uintptr_t get_string_ptr(uint8_t id) {
83+
//printf("C get_string_ptr(%d): %p\n", id, D[id]);
84+
return (uintptr_t)D[id];
85+
}
86+
87+
// External through functions (mode = extfnc)
88+
89+
void write_char(uint8_t id, uint32_t i, uint8_t v ) {
90+
//printf("C write_char(%d, %d): %d\n", id, i, v);
91+
D[id][i] = v;
92+
}
93+
94+
uint8_t read_char(uint8_t id, uint32_t i) {
95+
//printf("C read_char(%d, %d): %d\n", id, i, D[id][i]);
96+
return D[id][i];
97+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
-- NOTE: This file is expected to be used along with foreign languages (C)
8+
-- through VHPIDIRECT: https://ghdl.readthedocs.io/en/latest/using/Foreign.html
9+
-- See main.c for an example of a wrapper application.
10+
11+
--library vunit_lib;
12+
--context vunit_lib.vunit_context;
13+
14+
library vunit_lib;
15+
use vunit_lib.run_pkg.all;
16+
use vunit_lib.logger_pkg.all;
17+
use vunit_lib.types_pkg.all;
18+
use vunit_lib.byte_vector_ptr_pkg.all;
19+
20+
entity tb_external_byte_vector is
21+
generic ( runner_cfg : string );
22+
end entity;
23+
24+
architecture tb of tb_external_byte_vector is
25+
26+
constant block_len : natural := 5;
27+
28+
constant ebuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extfnc, 0); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
29+
constant abuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extacc, 0); -- external through access (requires VHPIDIRECT function 'get_string_ptr')
30+
31+
begin
32+
33+
main: process
34+
variable val, ind: integer;
35+
begin
36+
test_runner_setup(runner, runner_cfg);
37+
info("Init test");
38+
for x in 0 to block_len-1 loop
39+
val := get(ebuf, x) + 1;
40+
ind := block_len+x;
41+
set(ebuf, ind, val);
42+
info("SET " & to_string(ind) & ": " & to_string(val));
43+
end loop;
44+
for x in block_len to 2*block_len-1 loop
45+
val := get(abuf, x) + 2;
46+
ind := block_len+x;
47+
set(abuf, ind, val);
48+
info("SET " & to_string(ind) & ": " & to_string(val));
49+
end loop;
50+
info("End test");
51+
test_runner_cleanup(runner);
52+
wait;
53+
end process;
54+
55+
end architecture;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
-- NOTE: This file is expected to be used along with foreign languages (C)
8+
-- through VHPIDIRECT: https://ghdl.readthedocs.io/en/latest/using/Foreign.html
9+
-- See main.c for an example of a wrapper application.
10+
11+
--library vunit_lib;
12+
--context vunit_lib.vunit_context;
13+
14+
library vunit_lib;
15+
use vunit_lib.run_pkg.all;
16+
use vunit_lib.logger_pkg.all;
17+
use vunit_lib.types_pkg.all;
18+
use vunit_lib.string_ptr_pkg.all;
19+
20+
entity tb_external_string is
21+
generic ( runner_cfg : string );
22+
end entity;
23+
24+
architecture tb of tb_external_string is
25+
26+
constant block_len : natural := 5;
27+
28+
constant ebuf: string_ptr_t := new_string_ptr( 3*block_len, extfnc, 0); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
29+
constant abuf: string_ptr_t := new_string_ptr( 3*block_len, extacc, 0); -- external through access (requires VHPIDIRECT function 'get_string_ptr')
30+
31+
begin
32+
33+
main: process
34+
variable val, ind: integer;
35+
begin
36+
test_runner_setup(runner, runner_cfg);
37+
info("Init test");
38+
for x in 1 to block_len loop
39+
val := character'pos(get(ebuf, x)) + 1;
40+
ind := block_len+x;
41+
set(ebuf, ind, character'val(val));
42+
info("SET " & to_string(ind) & ": " & to_string(val));
43+
end loop;
44+
for x in block_len+1 to 2*block_len loop
45+
val := character'pos(get(abuf, x)) + 2;
46+
ind := block_len+x;
47+
set(abuf, ind, character'val(val));
48+
info("SET " & to_string(ind) & ": " & to_string(val));
49+
end loop;
50+
info("End test");
51+
test_runner_cleanup(runner);
52+
wait;
53+
end process;
54+
55+
end architecture;

vunit/test/acceptance/test_external_run_scripts.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import sys
1717
from vunit import ROOT
1818
from vunit.builtins import VHDL_PATH
19-
from vunit.test.common import has_simulator, check_report, simulator_is
19+
from vunit.test.common import has_simulator, check_report, simulator_is, simulator_check
2020

2121

2222
def simulator_supports_verilog():
@@ -117,6 +117,13 @@ def test_vhdl_array_axis_vcs_example_project(self):
117117
def test_vhdl_axi_dma_example_project(self):
118118
self.check(join(ROOT, "examples", "vhdl", "axi_dma", "run.py"))
119119

120+
@unittest.skipIf(
121+
simulator_check(lambda simclass: not simclass.supports_vhpi()),
122+
"This simulator/backend does not support interfacing with external C code"
123+
)
124+
def test_vhdl_external_buffer_project(self):
125+
self.check(join(ROOT, "examples", "vhdl", "external_buffer", "run.py"))
126+
120127
def test_vhdl_user_guide_example_project(self):
121128
self.check(join(ROOT, "examples", "vhdl", "user_guide", "run.py"), exit_code=1)
122129
check_report(self.report_file,

vunit/vhdl/data_types/src/byte_vector_ptr_pkg.vhd

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package byte_vector_ptr_pkg is
1717

1818
alias val_t is byte_t;
1919

20-
alias storage_mode_t is work.string_ptr_pkg.storage_mode_t;
2120
alias byte_vector_ptr_t is string_ptr_t;
2221
alias null_byte_vector_ptr is null_string_ptr;
2322

@@ -30,7 +29,7 @@ package byte_vector_ptr_pkg is
3029
impure function new_byte_vector_ptr (
3130
length : natural := 0;
3231
mode : storage_mode_t := internal;
33-
id : integer := 0;
32+
eid : index_t := -1;
3433
value : val_t := 0
3534
) return ptr_t;
3635

@@ -63,10 +62,10 @@ package body byte_vector_ptr_pkg is
6362
impure function new_byte_vector_ptr (
6463
length : natural := 0;
6564
mode : storage_mode_t := internal;
66-
id : integer := 0;
65+
eid : index_t := -1;
6766
value : val_t := 0
6867
) return ptr_t is begin
69-
return work.string_ptr_pkg.new_string_ptr(length, mode, id, character'val(value));
68+
return work.string_ptr_pkg.new_string_ptr(length, mode, eid, character'val(value));
7069
end;
7170

7271
procedure set (

0 commit comments

Comments
 (0)