Skip to content

Commit fa5d6ed

Browse files
committed
add(examples/vhdl/external_buffer)
1 parent 3547b24 commit fa5d6ed

5 files changed

Lines changed: 265 additions & 1 deletion

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+
Interfacing with foreign languages (C) through VHPIDIRECT:
11+
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+
33+
src_path = join(dirname(__file__), 'src')
34+
35+
c_obj = join(src_path, 'main.o')
36+
# Compile C application to an object
37+
print(popen(' '.join([
38+
'gcc', '-fPIC',
39+
'-c', join(src_path, 'main.c'),
40+
'-o', c_obj
41+
])).read())
42+
43+
# Enable the external feature for strings
44+
ui = VUnit.from_argv(vhdl_standard='2008', external={'string': True})
45+
46+
lib = ui.add_library('lib')
47+
lib.add_source_files(join(src_path, '*.vhd'))
48+
49+
# Add the C object to the elaboration of GHDL
50+
ui.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj])
51+
52+
ui.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<0)
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>0)
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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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.byte_vector_ptr_pkg.all;
18+
19+
entity tb_external_byte_vector is
20+
generic ( runner_cfg : string );
21+
end entity;
22+
23+
architecture tb of tb_external_byte_vector is
24+
25+
constant block_len : natural := 5;
26+
27+
constant ebuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extfnc); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
28+
constant abuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extacc); -- external through access (requires VHPIDIRECT function 'get_string_ptr')
29+
30+
begin
31+
32+
main: process
33+
variable val, ind: integer;
34+
begin
35+
test_runner_setup(runner, runner_cfg);
36+
info("Init test");
37+
for x in 0 to block_len-1 loop
38+
val := get(ebuf, x) + 1;
39+
ind := block_len+x;
40+
set(ebuf, ind, val);
41+
info("SET " & to_string(ind) & ": " & to_string(val));
42+
end loop;
43+
for x in block_len to 2*block_len-1 loop
44+
val := get(abuf, x) + 2;
45+
ind := block_len+x;
46+
set(abuf, ind, val);
47+
info("SET " & to_string(ind) & ": " & to_string(val));
48+
end loop;
49+
info("End test");
50+
test_runner_cleanup(runner);
51+
wait;
52+
end process;
53+
54+
end architecture;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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.string_ptr_pkg.all;
18+
19+
entity tb_external_string is
20+
generic ( runner_cfg : string );
21+
end entity;
22+
23+
architecture tb of tb_external_string is
24+
25+
constant block_len : natural := 5;
26+
27+
constant ebuf: string_ptr_t := new_string_ptr( 3*block_len, extfnc); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
28+
constant abuf: string_ptr_t := new_string_ptr( 3*block_len, extacc); -- external through access (requires VHPIDIRECT function 'get_string_ptr')
29+
30+
begin
31+
32+
main: process
33+
variable val, ind: integer;
34+
begin
35+
test_runner_setup(runner, runner_cfg);
36+
info("Init test");
37+
for x in 1 to block_len loop
38+
val := get(ebuf, x) + 1;
39+
ind := block_len+x;
40+
set(ebuf, ind, val);
41+
info("SET " & to_string(ind) & ": " & to_string(val));
42+
end loop;
43+
for x in block_len+1 to 2*block_len loop
44+
val := get(abuf, x) + 2;
45+
ind := block_len+x;
46+
set(abuf, ind, val);
47+
info("SET " & to_string(ind) & ": " & to_string(val));
48+
end loop;
49+
info("End test");
50+
test_runner_cleanup(runner);
51+
wait;
52+
end process;
53+
54+
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():
@@ -115,6 +115,13 @@ def test_vhdl_array_axis_vcs_example_project(self):
115115
def test_vhdl_axi_dma_example_project(self):
116116
self.check(join(ROOT, "examples", "vhdl", "axi_dma", "run.py"))
117117

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

0 commit comments

Comments
 (0)