Closed drizzd closed 7 years ago
Ok, so for example this works for me:
from shutil import copy
copy(mifPath, ui._simulator_factory.simulator_output_path)
Is it possible to use an environment variable in the mif file path such as PROJECT_ROOT? An environment variable can be set in the run.py script.
Your suggested solution has theoretical problems with parallel simulation and mif files with common base name.
Unrelated to VUnit and maybe unhelpful but another solution is to never use mif files. I always infer block ram and ROMs. Inferring them leads to significantly faster simulation and enables generic/parameters to influence the memory.
@kraigher In my experience the path to the mif file is hard coded in the simulation wrapper vhdl file. Unless you want to modify this file (which I avoid at all costs), then there is no way to specify a different name/path for the mif.
What is the problem with parallel simulation? Multiple simulators are not allowed to read from the same *mif at once? I do agree that there is a potential problem if you have mif files from different IP that end up getting named the same thing and then thrown into the same folder.
I agree that avoiding these types of files when possible is good practice, but sometimes it is just not worth it. For example, a FIR filter might use a mif file to simulate the configured coefficients.
@drizzd So is this issue resolved then?
The parallel simulation problem I was referring to was when different IP have a mif file named the same but with different content. Each simulation thread needs to have their own working directory to mitigate this.
@joshrsmith The member _simulator_factory starts with an underscore, which usually indicates that it is not a public interface. It is also not documented in the VUnit public API. If you say that you will support this also in the future, then this issue is resolved.
Note that currently, the simulator is detected and the simulation directory is created when VUnit is instantiated. Maybe in the future VUnit will delay this until the simulation actually runs. In this case, we would need a callback like pre_config to communicate the simulation directory to the user.
@kraigher My plan is to require that .mif file names must be unique within a project. But of course it is dangerous if a conflict ever goes unnoticed. Don't we already have a similar problem with external libraries or anything else which gets added to modelsim.ini? Maybe a unique simulation directory is indeed the right solution.
Alternatively, I could take the VHDL wrapper and blindly replace the string "my_rom.mif" with "$PROJECT_ROOT/path/to/my_rom.mif". But I am not sure if this will always work.
I would also prefer to use inference and I have not given up on that front. But I get a lot of resistance against its use. I am told that inference has led to problems in the past. People seem to fear a loss of control over the synthesis result. In any event, at least a few .mif files are likely to stay.
I will also try to submit a support request to Xilinx. But when I tried yesterday, the Xilinx website ate my request.
I is a true that the method suggested by @drizzd is not public and may change or disappear. If we make this public my initial thought is it will be through pre_config callback.
An alternative method is to "preprocess" the VHDL file to create a new VHDL file using a regex in the Python script which is then added to VUnit without modifying the original file.
BTW regarding parallel simulation and modelsim.ini it is no problem since it is never modified after the initial non-parallel part where all files are compiled.
I just recalled that the VHDL wrapper generated by Vivado (as opposed to Coregen) does not have the .mif file in the source code. It is a only a stub with an empty architecture and several attributes. I don't know how it determines where to read the .mif file, but preprocessing may not help here. I will try to find out more on Monday.
Just for clarification: the only way to get a .mif file conflict is by selecting different IP with same .mif basename but different content. There can be only one toplevel Testbench per VUnit instance (i.e. per run.py). Is this correct?
If so we could mitigate the danger of conflict by providing an interfaces which takes a list of files to copy to the simulation directory. It will do so only once for all configurations and it will error out if the basenames are not unique.
It is possible to have many testbenches in a run.py. At work I have the entire project with ~100 testbenches accessible through the run.py.
Ah, I see. My bad.
Nevertheless if we make the "copy files to simulation directory" interface global rather than per-testbench or per-configuration, then we can check if the files are unique.
I discarded my "copy files to simulation directory" interface idea because this solution is too specific for VUnit. The user can do such checks on their own and hopefully the burden will convince them to use inference in the future.
I forgot to document the simulation_output_path parameter in add_config's docstring. I will fix this if you want to go with this change.
Any thoughts on the pull request? It is a minimal implementation according to kraigher's comment "If we make this public my initial thought is it will be through pre_config callback."
I hint at the potential issues in the API documentation:
The function accepts an optional first argument `output_path` which is the filesystem path to the
directory where test outputs are stored. An optional second argument
`simulator_output_path` is the filesystem path to the simulator working directory.
Please note that `simulator_output_path` is shared by all test runs. The user must take
care that test runs do not read or write the same files asynchronously. It is therefore
recommended to use `output_path` in favor of `simulator_output_path`.
The problem can be completely removed if all paths to mif files are absolute paths. However, this is not possible for the automatically generated IP. The issue of memory files not being found by simulators due to the simulator path being at a different level in hierarchy than the synthesis tool is an old one. A proper solution would require some cooperation from the simulator and synthesis tool vendors!
As far as VUnit is concerned, the ideal solution would be that we can specify the memory files along with their location relative to the simulator path and that these files are copied before the simulator is fired up or atleast before the source files are compiled. The issue of different memory files having the same name is really something that the user should be aware of and deal with. VUnit can make detection of such conflicts easier of course.
The pre-simulation hook script is executed once all the files have been compiled. It is not the write place. It might be better to have a pre-elaboration hook as well.
IP generators such as Xilinx Coregen produce VHDL wrapper files for simulating the core. Memory initialization files (.mif) which contain the initialization vectors are generated for certain cores, for example ROMs and RAMs. The VHDL wrapper file hardcodes the path to the .mif file. Here is an example ROM wrapper:
Simulating this in Modelsim with VUnit will produce the following error:
Of course it cannot find it, because VUnit will start vsim in the vunit_out/modelsim directory. My first workaround will be to copy the .mif file to vunit_out/modelsim before running ui.main(). But it would be nice if I could use the VUnit API to determine the simulation directory, preferably in a callback which is invoked after VUnit has created it.
As far as I can tell, cores generated with Vivado have the same issue.