-
Notifications
You must be signed in to change notification settings - Fork 9
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
Various VPI examples #19
base: master
Are you sure you want to change the base?
Changes from all commits
97e51da
1d6b84c
52975d3
0d5789d
f478d8f
3297c11
f30f585
7fd3508
f09c924
9efed06
a684de7
93ba510
976dcf5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,9 @@ | |
*.lst | ||
*.o | ||
*.so | ||
*.vpi | ||
ent* | ||
tb* | ||
!*.vhd | ||
!*.vhdl | ||
doc/_build/* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
Examples | ||
######## | ||
|
||
TBC | ||
.. toctree:: | ||
|
||
quickstart | ||
list |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
List | ||
#### | ||
|
||
:cosimtree:`list <vpi/list>` | ||
**************************** |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
Quickstart | ||
########## | ||
|
||
:cosimtree:`helloworld <vpi/quickstart/helloworld>` | ||
*************************************************** | ||
|
||
:cosimtree:`begin_end <vpi/quickstart/begin_end>` | ||
************************************************* | ||
|
||
:cosimtree:`access <vpi/quickstart/access>` | ||
******************************************* | ||
|
||
:cosimtree:`access_port <vpi/quickstart/access_port>` | ||
***************************************************** | ||
|
||
:cosimtree:`timestep <vpi/quickstart/timestep>` | ||
*********************************************** | ||
|
||
|
||
|
||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
## VPI examples | ||
|
||
The directory contains some VPI usage examples: | ||
|
||
1. [quickstart/helloworld](./quickstart/helloworld/) minimal VPI code example that runs a simulation, prints a message and exits. | ||
2. [quickstart/begin_end](./quickstart/begin_end/) VPI code example that executes a callback at the begin and the end of a simulation. | ||
3. [quickstart/access](./quickstart/access/) signal read/write example on an adder component using `vpi_put_value` and `vpi_get_value`. | ||
4. [quickstart/access_port](./quickstart/access_port/) toplevel ports read/write example on an adder component using `vpi_put_value` and `vpi_get_value`. | ||
5. [quickstart/timestep](./quickstart/timestep/) shows how to run a simulation for an arbitrary number of timesteps. | ||
6. [list](./list/) example on signal hierarchy iteration using `vpi_iterate`and `vpi_scan`. | ||
|
||
to run a test, just go in the directory and execute | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment applies to all the examples in this repo. It would better fit either as an admonition in the main page, or in the README. It can be a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should go in the main README, along with an explanation about "groups of examples" (see #19 (comment)). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now included in #21. |
||
```bash | ||
sh run.sh | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#pragma once | ||
#include <inttypes.h> | ||
#include <vpi_user.h> | ||
|
||
/* | ||
* register_cb is a wrapper function around vpi_register_cb | ||
* to simplify the the callback registering process | ||
*/ | ||
void register_cb(PLI_INT32(*f)(p_cb_data), | ||
PLI_INT32 reason, | ||
int64_t cycles){ | ||
|
||
s_cb_data cbData; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that this deserves a reference/cite, either here or in the docs. Where should users search for the definition of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now explained in #21. |
||
s_vpi_time simuTime; | ||
if (cycles < 0){ | ||
cbData.time = NULL; | ||
} else { | ||
cbData.time = &simuTime; | ||
simuTime.type = vpiSimTime; | ||
simuTime.high = (PLI_INT32) (cycles >> 32); | ||
simuTime.low = (PLI_INT32) (cycles & 0xFFFFFFFF); | ||
} | ||
|
||
cbData.reason = reason; | ||
cbData.cb_rtn = f; | ||
cbData.user_data = 0; | ||
cbData.value = 0; | ||
|
||
vpi_register_cb(&cbData); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
library ieee; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment about duplicated files above. |
||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
-- ent is a 4 bit adder | ||
|
||
entity ent is | ||
port(nibble1, nibble2 : in unsigned(3 downto 0); | ||
sum : out unsigned(3 downto 0); | ||
carry_out : out std_logic); | ||
|
||
end entity ent; | ||
|
||
architecture behavioral of ent is | ||
|
||
signal temp : unsigned(4 downto 0); | ||
|
||
begin | ||
|
||
temp <= ("0" & nibble1) + nibble2; | ||
sum <= temp(3 downto 0); | ||
carry_out <= temp(4); | ||
|
||
end architecture behavioral; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/usr/bin/env sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment about duplicated files above. |
||
|
||
set -e | ||
|
||
cd "$(dirname $0)" | ||
|
||
PATH=$PATH:$(pwd) | ||
|
||
echo "Analyze ent.vhd and tb.vhd" | ||
ghdl -a ent.vhd tb.vhd | ||
|
||
echo "Elaborate tb" | ||
ghdl -e tb | ||
|
||
echo "Compile vpi.c" | ||
ghdl --vpi-compile gcc -c vpi.c -I./../ -o vpi.o | ||
|
||
echo "Link vpi.o" | ||
ghdl --vpi-link gcc vpi.o -o vpi.vpi | ||
|
||
echo "Execute tb" | ||
ghdl -r tb --vpi=./vpi.vpi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
library ieee; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment about duplicated files above. |
||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
entity tb is | ||
end tb; | ||
|
||
architecture behavioral of tb is | ||
|
||
signal nibble1, nibble2 : unsigned(3 downto 0); | ||
signal sum_0, sum_1, sum_2, sum_3 : unsigned(3 downto 0); | ||
signal carry_out_0, carry_out_1, carry_out_2, carry_out_3: std_logic; | ||
|
||
begin | ||
|
||
ent_0: entity work.ent | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels not to be valid VHDL. Is it on purpose? Anyway, correct or purposely incorrect, I'd suggest to use a i_ent: for I in 0 to 3 generate
w_ent: entity work.ent
port map (nibble1 => nibble1,
nibble2 => nibble2,
sum => sum,
carry_out => carry_out);
end generate; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The script is running, the CI completes without any error, and GHDL doesn't pop out even a Warning. Therefore I think it is valid VHDL. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surprising... I would expect Anyway, I think we should build a proper adder chain to sum two 4*4=16bit numbers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, now I see that you were talking about a multiple-driving issue. I agree that it is strange that GHDL doesn't catch it and I will fix that. Please could you be a bit more descriptive and giving the code lines where the problem is next time? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sure! Sorry about it. I was convinced that you had done it on purpose, because you only wanted to explore the hierarchy without caring about the content. I will take care of fixing this source if you want; so you can focus on VPI-specific issues which I'm less comfortable with. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Equivalent source included in #21. |
||
port map (nibble1 => nibble1, | ||
nibble2 => nibble2, | ||
sum => sum_0, | ||
carry_out => carry_out_0); | ||
|
||
ent_1: entity work.ent | ||
port map (nibble1 => nibble1, | ||
nibble2 => nibble2, | ||
sum => sum_1, | ||
carry_out => carry_out_1); | ||
|
||
ent_2: entity work.ent | ||
port map (nibble1 => nibble1, | ||
nibble2 => nibble2, | ||
sum => sum_2, | ||
carry_out => carry_out_2); | ||
|
||
ent_3: entity work.ent | ||
port map (nibble1 => nibble1, | ||
nibble2 => nibble2, | ||
sum => sum_3, | ||
carry_out => carry_out_3); | ||
process | ||
|
||
begin | ||
|
||
wait for 10 ns; | ||
wait; | ||
|
||
end process; | ||
|
||
end architecture behavioral; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
#include <vpi_user.h> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that all VHDL sources are the same for all the examples. Do you think that it can be a common pattern for all VPI examples? Or do you expect other features to require different VHDL sources? I ask it because it seems that the 4-7 examples that are part of this PR differ on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing is that to demonstrate very basic usage of VPI, the VHDL component under test do not matter so much. So, for helloworld I can, for example, just put a complete void top module without any signals, because at the end the VPI code is interacting with the simulator but not with the simulation. If you think it is better, I can try to make the ent.vhd and tb.vhd even more concise in each test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This. In VHPIDIRECT examples, many C sources are common but VHDL sources need to be different. Here, as you said, VHDL sources are almost irrelevant (as long as they contain the minimum features that we want to test). Hence, instead of making |
||
#include <stdio.h> | ||
#include "common_vpi.h" | ||
|
||
void print_net_in_module(vpiHandle module_handle) { | ||
char* module_name = vpi_get_str(vpiName, module_handle); | ||
vpiHandle net_handle; | ||
|
||
printf(" Signals of %s: \n", module_name); | ||
vpiHandle net_iterator = vpi_iterate(vpiNet,module_handle); | ||
if(net_iterator){ | ||
while(net_handle = vpi_scan(net_iterator)){ | ||
char* net_full_name = vpi_get_str(vpiFullName, net_handle); | ||
printf(" %s \n", net_full_name); | ||
vpi_free_object(net_handle); | ||
} | ||
} | ||
} | ||
|
||
void print_signals(){ | ||
|
||
vpiHandle top_mod_iterator; | ||
vpiHandle top_mod_handle; | ||
|
||
top_mod_iterator = vpi_iterate(vpiModule,NULL); | ||
|
||
top_mod_handle = vpi_scan(top_mod_iterator); | ||
while(top_mod_handle) { | ||
print_net_in_module(top_mod_handle); | ||
vpiHandle module_iterator = vpi_iterate(vpiModule,top_mod_handle); | ||
if (module_iterator){ | ||
vpiHandle module_handle; | ||
module_handle = vpi_scan(module_iterator); | ||
while (module_handle) { | ||
print_net_in_module(module_handle); | ||
vpi_free_object(module_handle); | ||
module_handle = vpi_scan(module_iterator); | ||
} | ||
} | ||
vpi_free_object(top_mod_handle); | ||
top_mod_handle = vpi_scan(top_mod_iterator); | ||
} | ||
} | ||
|
||
PLI_INT32 start_cb(p_cb_data data){ | ||
(void) data; | ||
|
||
printf("List of simulation signals: \n"); | ||
print_signals(); | ||
|
||
return 0; | ||
} | ||
|
||
void entry_point_cb() { | ||
register_cb(start_cb, cbStartOfSimulation, -1); | ||
} | ||
|
||
void (*vlog_startup_routines[]) () = { | ||
entry_point_cb, | ||
0 | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/usr/bin/env sh | ||
|
||
set -e | ||
|
||
cd "$(dirname $0)" | ||
|
||
PATH=$PATH:$(pwd) | ||
|
||
echo "Analyze tb.vhd" | ||
ghdl -a tb.vhd | ||
|
||
echo "Elaborate tb" | ||
ghdl -e tb | ||
|
||
echo "Compile vpi.c" | ||
ghdl --vpi-compile gcc -c vpi.c -I./../../ -o vpi.o | ||
|
||
echo "Link vpi.o" | ||
ghdl --vpi-link gcc vpi.o -o vpi.vpi | ||
|
||
echo "Execute tb" | ||
ghdl -r tb --vpi=./vpi.vpi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
entity tb is | ||
end tb; | ||
|
||
architecture behavioral of tb is | ||
|
||
signal nibble1, nibble2, sum : unsigned(3 downto 0); | ||
|
||
begin | ||
|
||
process | ||
|
||
begin | ||
|
||
wait for 10 ns; | ||
wait; | ||
|
||
end process; | ||
|
||
sum <= nibble1 + nibble2; | ||
|
||
end architecture behavioral; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#include <vpi_user.h> | ||
#include <stdio.h> | ||
#include "common_vpi.h" | ||
|
||
PLI_INT32 start_cb(p_cb_data data){ | ||
(void) data; | ||
|
||
// VPI value structure | ||
s_vpi_value val; | ||
|
||
// type of data format that is passed to the runtime. | ||
val.format = vpiBinStrVal; | ||
val.value.str = "0101"; | ||
printf("set %s in tb.nibble1 \n", val.value.str); | ||
|
||
//vpi_handle_by_name returns an arbitrary port/signal in the | ||
//simulation hierarchy | ||
vpiHandle nibble1 = vpi_handle_by_name("tb.nibble1", NULL); | ||
|
||
//vpi_put_value set the value to the passed signal handle | ||
vpi_put_value(nibble1, &val, NULL, vpiNoDelay); | ||
|
||
val.value.str = "0011"; | ||
printf("set %s in tb.nibble2 \n", val.value.str); | ||
vpiHandle nibble2 = vpi_handle_by_name("tb.nibble2", NULL); | ||
vpi_put_value(nibble2, &val, NULL, vpiNoDelay); | ||
|
||
return 0; | ||
} | ||
|
||
PLI_INT32 end_cb(p_cb_data data){ | ||
(void) data; | ||
s_vpi_value val; | ||
|
||
val.format = vpiBinStrVal; | ||
vpiHandle sum = vpi_handle_by_name("tb.sum", NULL); | ||
|
||
//vpi_get_value reads the value from the passed signal handle | ||
vpi_get_value(sum, &val); | ||
printf("get %s from tb.sum \n", val.value.str); | ||
|
||
return 0; | ||
} | ||
|
||
void entry_point_cb() { | ||
register_cb(start_cb, cbStartOfSimulation, -1); | ||
register_cb(end_cb, cbEndOfSimulation, -1); | ||
} | ||
|
||
void (*vlog_startup_routines[]) () = { | ||
entry_point_cb, | ||
0 | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should be written in RST and located in subdir
doc
. The motivation to use RST is that we might want to add labels for cross-referencing these examples. The location is because we are keeping docs separate from code sources.Moreover, each example should have a header of the appropriate level. This is necessary for the TOC.
In VHPIDIRECT, examples are grouped (Quick start, Arrays, Other projects...). You might want to add all your examples to a section named "Quick Start", to use/create some other section, or to not create any section yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am ok with this. However, I just did a similar thing as in
./systemc/README.md
. If you think it is unnecessary I will remove that, but having a small overview of the folder is helpful for people that just want to explore the repo without directly using the documentation. See https://github.com/bellaz89/ghdl-cosim/tree/master/vpiThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, the existence of
./systemc/README.md
is a kind of "artifact". Repo https://github.com/ghdl/ghdl-systemc-fosdem15 was created some weeks ago, due to a user's demand. The name was not correct, and it was renamed to https://github.com/ghdl/ghdl-systemc-fosdem16 a few days later. Then, we discussed about widening the scope to "co-simulation", and this repo was forked from there. We considered to rename the other once again, but we thought it would be too much trouble. Nonetheless, the content of the "old" repo was moved to subdir./systemc
and the README remains. The plan is to add it to the docs (as other examples), once we guess how to make it fit.Honestly, I had not thought about it, but it sounds as a good idea! From this point of view:
The docs need not to link this file, but headers should link to the corresponding subdirs.vpi/README.md
? Two (vpi/quickstart/README.md
andvpi/list/README.md
)? Or all of them?