Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1/3] Add external models to string_ptr; add byte_vector* as an alias #507

Merged
merged 5 commits into from
Oct 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions examples/vhdl/external_buffer/cp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) 2014-2019, Lars Asplund [email protected]

from vunit import VUnit
from os import popen
from os.path import join, dirname

src_path = join(dirname(__file__), 'src')

c_obj = join(src_path, 'cp.o')
# Compile C application to an object
print(popen(' '.join([
'gcc', '-fPIC',
'-c', join(src_path, 'cp.c'),
'-o', c_obj
])).read())

# Enable the external feature for strings
vu = VUnit.from_argv(vhdl_standard='2008', compile_builtins=False)
vu.add_builtins({'string': True})

lib = vu.add_library('lib')
lib.add_source_files(join(src_path, 'tb_extcp_*.vhd'))

# Add the C object to the elaboration of GHDL
vu.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj])

vu.main()
52 changes: 52 additions & 0 deletions examples/vhdl/external_buffer/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# This Source Code Form is subject to the terms of the Mozilla Public
umarcor marked this conversation as resolved.
Show resolved Hide resolved
umarcor marked this conversation as resolved.
Show resolved Hide resolved
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) 2014-2019, Lars Asplund [email protected]

"""
External Buffer
---------------

`Interfacing with foreign languages (C) through VHPIDIRECT <https://ghdl.readthedocs.io/en/latest/using/Foreign.html>`_

An array of type ``uint8_t`` is allocated in a C application and some values
are written to the first ``1/3`` positions. Then, the VHDL simulation is
executed, where the (external) array/buffer is used.

In the VHDL testbenches, two vector pointers are created, each of them using
a different access mechanism (``extfunc`` or ``extacc``). One of them is used to copy
the first ``1/3`` elements to positions ``[1/3, 2/3)``, while incrementing each value
by one. The second one is used to copy elements from ``[1/3, 2/3)`` to ``[2/3, 3/3)``,
while incrementing each value by two.

When the simulation is finished, the C application checks whether data was successfully
copied/modified. The content of the buffer is printed both before and after the
simulation.
"""

from vunit import VUnit
from os import popen
from os.path import join, dirname

src_path = join(dirname(__file__), 'src')

c_obj = join(src_path, 'main.o')
# Compile C application to an object
print(popen(' '.join([
'gcc', '-fPIC',
'-c', join(src_path, 'main.c'),
'-o', c_obj
])).read())

# Enable the external feature for strings
vu = VUnit.from_argv(vhdl_standard='2008', compile_builtins=False)
vu.add_builtins({'string': True})

lib = vu.add_library('lib')
lib.add_source_files(join(src_path, 'tb_ext_*.vhd'))

# Add the C object to the elaboration of GHDL
vu.set_sim_option('ghdl.elab_flags', ['-Wl,' + c_obj])

vu.main()
96 changes: 96 additions & 0 deletions examples/vhdl/external_buffer/src/cp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
External Buffer

Interfacing with foreign languages (C) through VHPIDIRECT:
https://ghdl.readthedocs.io/en/latest/using/Foreign.html

Two arrays of type uint8_t are allocated and some values are written to the first.
Then, the VHDL simulation is executed, where the (external) array/buffer
is used. When the simulation is finished, the results are checked. The content of
the buffer is printed both before and after the simulation.

NOTE: This file is expected to be used along with tb_extcp_byte_vector.vhd or tb_extcp_string.vhd
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

extern int ghdl_main (int argc, char **argv);

uint8_t *D[1];
const uint32_t length = 10;

// Check procedure, to be executed when GHDL exits.
// The simulation is expected to copy the first 1/3 elements to positions [1/3, 2/3),
// while incrementing each value by one, and then copy elements from [1/3, 2/3) to
// [2/3, 3/3), while incrementing each value by two.
static void exit_handler(void) {
int i, j, z, k;
uint8_t expected, got;
k = 0;

for(i=0; i<length; i++) {
expected = D[0][i];
got = D[1][i];
if (expected != got) {
printf("check error %d: %d %d\n", i, expected, got);
exit(1);
}
printf("%d: %d\n", i, got);
}

free(D[0]);
free(D[1]);
}

// Main entrypoint of the application
int main(int argc, char **argv) {
// Allocate two buffers
int i;
for(i=0; i<2; i++) {
D[i] = (uint8_t *) malloc(length*sizeof(uint8_t));
if ( D[i] == NULL ) {
perror("execution of malloc() failed!\n");
return -1;
}
}
// Initialize the first buffer
for(i=0; i<length; i++) {
D[0][i] = (i+1)*11;
}
// Print all the buffer
for(i=0; i<length; i++) {
printf("%d: %d\n", i, D[0][i]);
}

// Register a function to be called when GHDL exits
atexit(exit_handler);

// Start the simulation
return ghdl_main(argc, argv);
}

// External through access (mode = extacc)

void set_string_ptr(uint8_t id, uint8_t *p) {
//printf("C set_string_ptr(%d, %p)\n", id, p);
D[id] = p;
}

uintptr_t get_string_ptr(uint8_t id) {
//printf("C get_string_ptr(%d): %p\n", id, D[id]);
return (uintptr_t)D[id];
}

// External through functions (mode = extfnc)

void write_char(uint8_t id, uint32_t i, uint8_t v ) {
//printf("C write_char(%d, %d): %d\n", id, i, v);
D[id][i] = v;
}

uint8_t read_char(uint8_t id, uint32_t i) {
//printf("C read_char(%d, %d): %d\n", id, i, D[id][i]);
return D[id][i];
}
97 changes: 97 additions & 0 deletions examples/vhdl/external_buffer/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
External Buffer

Interfacing with foreign languages (C) through VHPIDIRECT:
https://ghdl.readthedocs.io/en/latest/using/Foreign.html

An array of type uint8_t is allocated and some values are written to the first 1/3
positions. Then, the VHDL simulation is executed, where the (external) array/buffer
is used. When the simulation is finished, the results are checked. The content of
the buffer is printed both before and after the simulation.

NOTE: This file is expected to be used along with tb_ext_byte_vector.vhd or tb_ext_string.vhd
*/

#include <stdio.h>
umarcor marked this conversation as resolved.
Show resolved Hide resolved
#include <stdlib.h>
#include <stdint.h>

extern int ghdl_main (int argc, char **argv);

uint8_t *D[1];
const uint32_t length = 5;

// Check procedure, to be executed when GHDL exits.
// The simulation is expected to copy the first 1/3 elements to positions [1/3, 2/3),
// while incrementing each value by one, and then copy elements from [1/3, 2/3) to
// [2/3, 3/3), while incrementing each value by two.
static void exit_handler(void) {
int i, j, z, k;
uint8_t expected, got;
k = 0;
for (j=0; j<3; j++) {
umarcor marked this conversation as resolved.
Show resolved Hide resolved
k += j;
for(i=0; i<length; i++) {
z = (length*j)+i;

expected = (i+1)*11 + k;
got = D[0][z];
if (expected != got) {
printf("check error %d: %d %d\n", z, expected, got);
exit(1);
}
printf("%d: %d\n", z, got);
}
}
free(D[0]);
}

// Main entrypoint of the application
int main(int argc, char **argv) {
// Allocate a buffer which is three times the number of values
// that we want to copy/modify
D[0] = (uint8_t *) malloc(3*length*sizeof(uint8_t));
if ( D[0] == NULL ) {
perror("execution of malloc() failed!\n");
return -1;
}
// Initialize the first 1/3 of the buffer
int i;
for(i=0; i<length; i++) {
D[0][i] = (i+1)*11;
}
// Print all the buffer
for(i=0; i<3*length; i++) {
printf("%d: %d\n", i, D[0][i]);
}

// Register a function to be called when GHDL exits
atexit(exit_handler);

// Start the simulation
return ghdl_main(argc, argv);
}

// External through access (mode = extacc)

void set_string_ptr(uint8_t id, uint8_t *p) {
//printf("C set_string_ptr(%d, %p)\n", id, p);
D[id] = p;
}

uintptr_t get_string_ptr(uint8_t id) {
//printf("C get_string_ptr(%d): %p\n", id, D[id]);
return (uintptr_t)D[id];
}

// External through functions (mode = extfnc)

void write_char(uint8_t id, uint32_t i, uint8_t v ) {
//printf("C write_char(%d, %d): %d\n", id, i, v);
D[id][i] = v;
}

uint8_t read_char(uint8_t id, uint32_t i) {
//printf("C read_char(%d, %d): %d\n", id, i, D[id][i]);
return D[id][i];
}
55 changes: 55 additions & 0 deletions examples/vhdl/external_buffer/src/tb_ext_byte_vector.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
-- You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright (c) 2014-2019, Lars Asplund [email protected]

-- NOTE: This file is expected to be used along with foreign languages (C)
-- through VHPIDIRECT: https://ghdl.readthedocs.io/en/latest/using/Foreign.html
-- See main.c for an example of a wrapper application.

--library vunit_lib;
--context vunit_lib.vunit_context;

library vunit_lib;
use vunit_lib.run_pkg.all;
use vunit_lib.logger_pkg.all;
use vunit_lib.types_pkg.all;
use vunit_lib.byte_vector_ptr_pkg.all;

entity tb_external_byte_vector is
generic ( runner_cfg : string );
end entity;

architecture tb of tb_external_byte_vector is

constant block_len : natural := 5;

constant ebuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extfnc, 0); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
constant abuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extacc, 0); -- external through access (requires VHPIDIRECT function 'get_string_ptr')

begin

main: process
variable val, ind: integer;
begin
test_runner_setup(runner, runner_cfg);
info("Init test");
for x in 0 to block_len-1 loop
val := get(ebuf, x) + 1;
ind := block_len+x;
set(ebuf, ind, val);
info("SET " & to_string(ind) & ": " & to_string(val));
end loop;
for x in block_len to 2*block_len-1 loop
val := get(abuf, x) + 2;
ind := block_len+x;
set(abuf, ind, val);
info("SET " & to_string(ind) & ": " & to_string(val));
end loop;
info("End test");
test_runner_cleanup(runner);
wait;
end process;

end architecture;
55 changes: 55 additions & 0 deletions examples/vhdl/external_buffer/src/tb_ext_string.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
-- You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright (c) 2014-2019, Lars Asplund [email protected]

-- NOTE: This file is expected to be used along with foreign languages (C)
-- through VHPIDIRECT: https://ghdl.readthedocs.io/en/latest/using/Foreign.html
-- See main.c for an example of a wrapper application.

--library vunit_lib;
--context vunit_lib.vunit_context;

library vunit_lib;
use vunit_lib.run_pkg.all;
use vunit_lib.logger_pkg.all;
use vunit_lib.types_pkg.all;
use vunit_lib.string_ptr_pkg.all;

entity tb_external_string is
generic ( runner_cfg : string );
end entity;

architecture tb of tb_external_string is

constant block_len : natural := 5;

constant ebuf: string_ptr_t := new_string_ptr( 3*block_len, extfnc, 0); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
constant abuf: string_ptr_t := new_string_ptr( 3*block_len, extacc, 0); -- external through access (requires VHPIDIRECT function 'get_string_ptr')

begin

main: process
variable val, ind: integer;
begin
test_runner_setup(runner, runner_cfg);
info("Init test");
for x in 1 to block_len loop
val := character'pos(get(ebuf, x)) + 1;
ind := block_len+x;
set(ebuf, ind, character'val(val));
info("SET " & to_string(ind) & ": " & to_string(val));
end loop;
for x in block_len+1 to 2*block_len loop
val := character'pos(get(abuf, x)) + 2;
ind := block_len+x;
set(abuf, ind, character'val(val));
info("SET " & to_string(ind) & ": " & to_string(val));
end loop;
info("End test");
test_runner_cleanup(runner);
wait;
end process;

end architecture;
Loading