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

VUnitCoSim #568

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
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
3 changes: 3 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sphinx
sphinx-argparse
ablog
69 changes: 69 additions & 0 deletions examples/vhdl/external_buffer/cosim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# 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 lars.anders.asplund@gmail.com


from vunit.cosim import *
import ctypes
from os.path import join, dirname, isfile
from sys import argv
from json import load


if len(argv) != 2:
print("A single argument is required and supported!")
exit(1)

with open(
join(dirname(__file__), "vunit_out", "cosim", "%s.json" % argv[1])
) as json_file:
args = load(json_file)
if "integer" not in argv[1]:
new_buf = byte_buf
read_buf = read_byte_buf
else:
new_buf = int_buf
read_buf = read_int_buf

xargs = enc_args(args)

print("\nREGULAR EXECUTION")
ghdl = dlopen(args[0])
try:
ghdl.main(len(xargs) - 1, xargs)
# FIXME With VHDL 93, the execution is Aborted and Python exits here
except SystemExit as exc:
if exc.code != 0:
exit(exc.code)
dlclose(ghdl)

print("\nPYTHON ALLOCATION")
ghdl = dlopen(args[0])

data = [111, 122, 133, 144, 155]

# Two pointers/buffers are to be allocated
buf = [[] for c in range(2)]

# Allocate and initialize shared data buffer
buf[1] = new_buf(data + [0 for x in range(2 * len(data))])

# Fill 'params' vector
buf[0] = int_buf(
[-(2 ** 31) + 10, -(2 ** 31), 3, 0, len(data)] # clk_step # update # block_length
)

for x, v in enumerate(buf):
ghdl.set_string_ptr(x, v)

for i, v in enumerate(read_buf(buf[1])):
print("py " + str(i) + ": " + str(v))

ghdl.ghdl_main(len(xargs) - 1, xargs)

for i, v in enumerate(read_buf(buf[1])):
print("py " + str(i) + ": " + str(v))

dlclose(ghdl)
36 changes: 33 additions & 3 deletions examples/vhdl/external_buffer/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,21 @@
"""

from vunit import VUnit, ROOT
from os import popen
from sys import argv
from os import popen, makedirs
from os.path import join, dirname
from shutil import copyfile
import re


src_path = join(dirname(__file__), "src")
ext_srcs = join(ROOT, "vunit", "vhdl", "data_types", "src", "external", "ghdl")
build_only = False
if "--build" in argv:
argv.remove("--build")
build_only = True

# Compile C applications to an objects
# Compile C applications to objects
c_iobj = join(src_path, "imain.o")
c_bobj = join(src_path, "bmain.o")

Expand Down Expand Up @@ -76,4 +84,26 @@
overwrite=True,
)

vu.main()
if build_only:
vu.set_sim_option("ghdl.elab_e", True)
vu._args.elaborate = True

def post_func(results):
"""
Copy runtime args for each test/executable to output dir 'cosim'
"""
report = results.get_report()
cosim_args_dir = join(report.output_path, "cosim")
try:
makedirs(cosim_args_dir)
except FileExistsError:
pass
for key, val in report.tests.items():
copyfile(
join(val.path, "ghdl", "args.json"),
join(cosim_args_dir, "%s.json" % re.search("lib\.(.+)\.all", key)[1]),
)

vu.main(post_run=post_func)
else:
vu.main()
69 changes: 69 additions & 0 deletions examples/vhdl/external_buffer/serve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# 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 lars.anders.asplund@gmail.com

import ctypes
from os.path import join, dirname
from vunit import VUnit
from websim import *


root = dirname(__file__)


# Allocate and define shared data buffers

data = [3 * c for c in range(64)]

buf = [[] for c in range(2)]
buf[1] = byte_buf(data + [0 for x in range(2 * len(data))])

buf[0] = int_buf(
[-(2 ** 31) + 1, -(2 ** 31), 0, 1, len(data)] # clk_step, update, block_length
)


# Load args and define simulation callbacks

sim = None
args = [line.rstrip("\n") for line in open(join(root, "args.txt"))]


def load():
g = ctypes.CDLL(args[0])
sim.handler(g)

for idx, val in enumerate(buf):
g.set_string_ptr(idx, val)

xargs = enc_args(args)
return g.ghdl_main(len(xargs) - 1, xargs)


def update_cb():
p = read_int_buf(buf[0])[0:3]
p[0] -= -(2 ** 31)
p[1] -= -(2 ** 31)
return {
"name": "external_buffer",
"params": p,
"data": {"mem": read_byte_buf(buf[1])},
}


def unload():
dlclose(sim.handler())


# Instantiate WebSim and run server

sim = WebSim(
dist=join(root, "..", "vue", "dist"),
load_cb=load,
unload_cb=unload,
update_cb=update_cb,
)

sim.run()
26 changes: 26 additions & 0 deletions examples/vhdl/external_buffer/sigabrt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
When VHDL 1993 is used, the simulation is terminated with an `abort`, which prevents the user from running post-checks.
These are some snippets to test it. See https://github.com/VUnit/vunit/pull/469#issuecomment-485723516.

``` python
https://bugs.python.org/issue12423
def handler(signum, frame):
print('Signal handler called with signal', signum)
import signal
signal.signal(signal.SIGABRT, handler)
import os
os.abort()
```

``` c
#include <signal.h>

void sigabrtHandler(int sig_num)
{
// Reset handler to catch SIGINT next time. Refer http://en.cppreference.com/w/c/program/signal
signal(SIGABRT, sigabrtHandler);
printf("\nSIGABRT caught!\n");
fflush(stdout);
}

signal(SIGABRT, sigabrtHandler);
```
24 changes: 20 additions & 4 deletions examples/vhdl/external_buffer/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ or tb_ext_integer_vector.vhd
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include "vhpidirect_user.h"

const uint32_t length = 5;
Expand All @@ -41,7 +42,7 @@ static void exit_handler(void) {
z = (length*j)+i;

expected = (i+1)*11 + k;
got = ((TYPE*)D[0])[z];
got = ((TYPE*)D[1])[z];
if (expected != got) {
printf("check error %d: %d %d\n", z, expected, got);
exit(1);
Expand All @@ -50,26 +51,41 @@ static void exit_handler(void) {
}
}
free(D[0]);
free(D[1]);
}

// 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(TYPE));
D[0] = (uint8_t *) malloc(5*sizeof(int32_t));
if ( D[0] == NULL ) {
perror("execution of malloc() failed!\n");
return -1;
}

// Initialize 'params' array
int32_t *P = (int32_t*)D[0];
P[0] = INT_MIN+10;
P[1] = INT_MIN;
P[2] = 3; // clk_step
P[3] = 0; // update
P[4] = length; // block_length

// Initialize the first 1/3 of the buffer
D[1] = (uint8_t *) malloc(3*length*sizeof(TYPE));
if ( D[1] == NULL ) {
perror("execution of malloc() failed!\n");
return -1;
}
int i;
for(i=0; i<length; i++) {
((TYPE*)D[0])[i] = (i+1)*11;
((TYPE*)D[1])[i] = (i+1)*11;
}
// Print all the buffer
printf("sizeof: %lu\n", sizeof(TYPE));
for(i=0; i<3*length; i++) {
printf("%d: %d\n", i, ((TYPE*)D[0])[i]);
printf("%d: %d\n", i, ((TYPE*)D[1])[i]);
}

// Register a function to be called when GHDL exits
Expand Down
56 changes: 48 additions & 8 deletions examples/vhdl/external_buffer/src/tb_ext_byte_vector.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,84 @@
--library vunit_lib;
--context vunit_lib.vunit_context;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

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;
use vunit_lib.integer_vector_ptr_pkg.all;
use vunit_lib.clk_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 params: integer_vector_ptr_t := new_integer_vector_ptr(6, extacc, 0);

constant clk_step : natural := get(params, 2);
constant block_len : integer := get(params, 4);

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')
constant ebuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extfnc, 1); -- external through VHPIDIRECT functions 'read_char' and 'write_char'
constant abuf: byte_vector_ptr_t := new_byte_vector_ptr( 3*block_len, extacc, 1); -- external through access (requires VHPIDIRECT function 'get_string_ptr')

signal clk, rst, rstn : std_logic := '0';
signal done, tg, start : boolean := false;

begin

main: process
rstn <= not rst;

clk_gen: entity vunit_lib.clk_handler generic map ( params ) port map ( rst, clk, tg );

run: process(tg) begin if rising_edge(tg) then
info("UPDATE READY");
set(params, 3, 1);
end if; end process;

main: process begin
test_runner_setup(runner, runner_cfg);
rst <= '1';
info("Init test: " & to_string(block_len));
wait for 100 ns;
rst <= '0';
info("wait_load");
wait_load(params);
info("start");
start <= true;
info("wait_sync");
wait_sync(params, done, tg);
info("Test done");
test_runner_cleanup(runner);
wait;
end process;

stimuli: process
variable val, ind: integer;
begin
test_runner_setup(runner, runner_cfg);
info("Init test");
wait until start;
wait_for(clk, 1);
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));
wait_for(clk, 1);
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));
wait_for(clk, 1);
end loop;
info("End test");
test_runner_cleanup(runner);
info("done");
done <= true;
wait;
end process;

Expand Down
4 changes: 2 additions & 2 deletions examples/vhdl/external_buffer/src/tb_ext_integer_vector.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ architecture tb of tb_external_integer_vector is

constant block_len : natural := 5;

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

begin

Expand Down
Loading