Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
sim:file [2024/02/26 18:38] fabian created |
sim:file [2024/02/27 12:16] (current) fabian |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== File interaction ====== | ====== File interaction ====== | ||
- | This library exports functions for basic file interaction. Files in actsim can be accessed using the common simulator prefix and file IDs. The common prefix is set using an actsim configuration file. The following is a snippet from the default actsim configuration. | + | This library exports functions for basic file interaction. |
+ | |||
+ | Files in actsim can be accessed using the common simulator prefix and file IDs. The common prefix is set using an actsim configuration file. The following is a snippet from the default actsim configuration. | ||
< | < | ||
Line 45: | Line 47: | ||
We will go over a simple example for reading an input file. Input files can provide integers of up to 32 bid width. Numbers are interpreted as base 10 by default, base 16, 8, and 2 are also allowed by the use of prefixes. Input files also support comments using ''#'' | We will go over a simple example for reading an input file. Input files can provide integers of up to 32 bid width. Numbers are interpreted as base 10 by default, base 16, 8, and 2 are also allowed by the use of prefixes. Input files also support comments using ''#'' | ||
- | In this example, we will reconstruct | + | In this example, we will construct |
<code act> | <code act> | ||
Line 72: | Line 74: | ||
</ | </ | ||
- | '' | + | '' |
We have now opened file 0 for reading and saved the reader ID in '' | We have now opened file 0 for reading and saved the reader ID in '' | ||
Line 140: | Line 142: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | ===== File writer example ===== | ||
+ | |||
+ | We will go over a simple example for writing an output file. Without writing C code, which hooks into the already provided API, the file writer can only push simple integer values to an output file. | ||
+ | |||
+ | In this example, we will construct a simple file sink, which writes to '' | ||
+ | |||
+ | <code act> | ||
+ | defproc sink_file (chan!(int< | ||
+ | { | ||
+ | int< | ||
+ | int writer_id; | ||
+ | bool success; | ||
+ | |||
+ | chp { | ||
+ | // we will put all further code here | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | File interactions are not synthesizable. All of our code is CHP based. You might have spotted the variables at the beginning of the block, we will explain them shortly. | ||
+ | |||
+ | First, we need to open the file for writing. This will return a writer ID, which is quite similar to a file descriptor on POSIX systems. As indicated by the comment, this will happen in the CHP block. | ||
+ | |||
+ | <code act> | ||
+ | // open the file and get a writer ID | ||
+ | writer_id := sim:: | ||
+ | |||
+ | // this is not necessary but good practice error checking | ||
+ | assert (writer_id != 0, "Oh no! We failed to open output file with ID 0!"); | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | We have now opened file 0 for writing and saved the writer ID in '' | ||
+ | |||
+ | <code act> | ||
+ | // receive the value and write to file | ||
+ | I?buf; | ||
+ | success := sim:: | ||
+ | </ | ||
+ | |||
+ | We want to repeat this process indefinitely (or until the simulation is ended). For this, we simply put these two steps into an infinite loop: | ||
+ | |||
+ | <code act> | ||
+ | *[ | ||
+ | // receive the value and write to file | ||
+ | I?buf; | ||
+ | success := sim:: | ||
+ | ]; | ||
+ | </ | ||
+ | |||
+ | Since we don't know how much data will be there, we'll assume the file will only be closed when the simulation ends. In this case, we don't need to explicitly close the file. | ||
+ | |||
+ | Putting things together, the full example looks like this: | ||
+ | |||
+ | <code act> | ||
+ | defproc sink_file (chan!(int< | ||
+ | { | ||
+ | int< | ||
+ | int writer_id; | ||
+ | bool success; | ||
+ | |||
+ | chp { | ||
+ | // open the file and get a writer ID | ||
+ | writer_id := sim:: | ||
+ | |||
+ | // this is not necessary but good practice error checking | ||
+ | assert (writer_id != 0, "Oh no! We failed to open output file with ID 0!"); | ||
+ | |||
+ | *[ | ||
+ | // receive the value and write to file | ||
+ | I?buf; | ||
+ | success := sim:: | ||
+ | ]; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Extending the File API ===== | ||
+ | |||
+ | File interactions can be extended using a shared C++ library, however the functions exposed to actsim must be made external C functions due to C++ name mangling. Include the '' | ||
+ | |||
+ | <code c> | ||
+ | extern " | ||
+ | expr_res ret; | ||
+ | ret.width = 1; | ||
+ | ret.v = 1; // on error we return 1 | ||
+ | |||
+ | // make sure we have the appropriate amount of arguments | ||
+ | if (argc != 5) { | ||
+ | std::cerr | ||
+ | << " | ||
+ | << std::endl; | ||
+ | return ret; | ||
+ | } | ||
+ | |||
+ | uint32_t writer_id = args[0].v; | ||
+ | uint8_t verbosity = args[1].v; | ||
+ | uint32_t logger_id = args[2].v; | ||
+ | uint32_t channel = args[3].v; | ||
+ | uint64_t value = args[4].v; | ||
+ | |||
+ | // build the log line | ||
+ | std:: | ||
+ | |||
+ | switch (verbosity) { | ||
+ | case 0: | ||
+ | builder << channel << ":" | ||
+ | break; | ||
+ | |||
+ | case 1: | ||
+ | builder << logger_id << " (" << channel << "): " << std::hex | ||
+ | << value << std::endl; | ||
+ | break; | ||
+ | |||
+ | case 2: | ||
+ | builder << " | ||
+ | << "): Received value " << value << "%x (0x" << std::hex | ||
+ | << value << " | ||
+ | |||
+ | default: | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | ret.v = actsim_file_write_core(writer_id, | ||
+ | return ret; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | When you have compiled your '' | ||
+ | |||
+ | < | ||
+ | begin extern | ||
+ | |||
+ | string_tablex libs " | ||
+ | |||
+ | begin mylib | ||
+ | string path "/ | ||
+ | |||
+ | # logger file output | ||
+ | string my_namespace:: | ||
+ | end | ||
+ | |||
+ | end | ||
+ | </ | ||
+ | |||
+ | And finally, make the function available to CHP: | ||
+ | |||
+ | <code act> | ||
+ | namespace my_namespace { | ||
+ | export function write_log (int< | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Mind the name change set in the actsim configuration! Functions in CHP must always return a value. If you do not need a return value, either use a boolean in combination with an assert function for error checking, or just read into a dummy variable. Not reading into anything will currently cause your function to be removed by the optimization pass. | ||
+ |