Differences

This shows you the differences between two versions of the page.

Link to this comparison view

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. The exposed functions enable you to read integer data from a basic input file, and to dump integer values into an output file. While this is rather basic, the file API can be extended using a shared C++ library and an actsim configuration file. 
 + 
 +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.
  
 <code> <code>
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 ''#'' as a prefix. Files can contain a trailing newline character after the last value, multiple newlines or comments after the last input value are currently not supported (to be changed in the future). 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 ''#'' as a prefix. Files can contain a trailing newline character after the last value, multiple newlines or comments after the last input value are currently not supported (to be changed in the future).
  
-In this example, we will reconstruct a simple file source which reads from ''infile.0'' using the simulation library (however, this library also already provides a fully functional one, see [[sim:sources | the page on sources]]).+In this example, we will construct a simple file sourcewhich reads from ''infile.0'' using the simulation library (however, this library also already provides a fully functional one, see [[sim:sources | the page on sources]], which we recommend using instead).
  
 <code act> <code act>
Line 72: Line 74:
 </code> </code>
  
-''openr'' will return a number larger than 0 if the file was successfully opened; a reader ID of 0 will indicate that something went wrong. It is good practice to make sure that everything worked; a call to ''assert'' is an easy solution for this.+''openr'' will return a number larger than 0if the file was successfully opened; a reader ID of 0 will indicate that something went wrong. It is good practice to make sure that everything worked; a call to ''assert'' is an easy solution for this.
  
 We have now opened file 0 for reading and saved the reader ID in ''reader_id''. The next step is to read a value: We have now opened file 0 for reading and saved the reader ID in ''reader_id''. The next step is to read a value:
Line 140: Line 142:
 } }
 </code> </code>
 +
 +===== 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 ''outfile.0'' using the simulation library (however, this library also already provides a fully functional one, see [[sim:sinks | the page on sinks]], which we recommend using instead).
 +
 +<code act>
 +defproc sink_file (chan!(int<32>) I)
 +{
 +    int<32> buf;
 +    int writer_id;
 +    bool success;
 +
 +    chp {
 +        // we will put all further code here
 +    }
 +}
 +</code>
 +
 +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::file::openw (0);
 +
 +// this is not necessary but good practice error checking
 +assert (writer_id != 0, "Oh no! We failed to open output file with ID 0!");
 +</code>
 +
 +''openw'' will return a number larger than 0, if the file was successfully opened; a writer ID of 0 will indicate that something went wrong. It is good practice to make sure that everything worked; a call to ''assert'' is an easy solution for this.
 +
 +We have now opened file 0 for writing and saved the writer ID in ''writer_id''. The next step is to receive a value from the input channel and write it to the file:
 +
 +<code act>
 +// receive the value and write to file
 +I?buf;
 +success := sim::file::write (write_id, buf)
 +</code>
 +
 +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::file::write (write_id, buf)
 +];
 +</code>
 +
 +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<32>) I)
 +{
 +    int<32> buf;
 +    int writer_id;
 +    bool success;
 +
 +    chp {
 +        // open the file and get a writer ID
 +        writer_id := sim::file::openw (0);
 +
 +        // 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::file::write (write_id, buf)
 +        ];
 +    }
 +}
 +</code>
 +
 +===== 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 ''simlib_file.h'' header to access the core file functions. With this, cou can use ''actsim_file_write_core'' to write your own custom output generator. Here is a brief example taken from the [[sim:loggers | logger]] output generation. For more information about the structure of an external C function callable from CHP, as well as how to make it accessible to actsim, see [[tools:actsim | the actsim page]] or read the default ''actsim.conf'' in the actsim source code in the ''simlib/'' directory.
 +
 +<code c>
 +extern "C" expr_res actsim_file_write_log(int argc, struct expr_res* args) {
 +    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
 +            << "actim_file_write_log: Must be invoked with 5 arguments only"
 +            << 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::ostringstream builder;
 +
 +    switch (verbosity) {
 +        case 0:
 +            builder << channel << ":" << std::hex << value << std::endl;
 +            break;
 +
 +        case 1:
 +            builder << logger_id << " (" << channel << "): " << std::hex
 +                    << value << std::endl;
 +            break;
 +
 +        case 2:
 +            builder << "Logger " << logger_id << " (Channel " << channel
 +                    << "): Received value " << value << "%x (0x" << std::hex
 +                    << value << ")" << std::endl;
 +
 +        default:
 +            break;
 +    }
 +
 +    ret.v = actsim_file_write_core(writer_id, builder.str());
 +    return ret;
 +}
 +</code>
 +
 +When you have compiled your ''.so'', you need to make the library available to actsim via a configuration file:
 +
 +<code>
 +begin extern
 +
 +    string_tablex libs "mylib"
 +
 +    begin mylib
 +        string path "/some/path/to/my_external_lib.so"
 +
 +        # logger file output
 +        string my_namespace::write_log      "actsim_file_write_log"
 +    end
 +
 +end
 +</code>
 +
 +And finally, make the function available to CHP:
 +
 +<code act>
 +namespace my_namespace {
 +export function write_log (int<32> writer_id; int<8> verbosity; int<32> log_id, channel; int<64> val) : bool;
 +}
 +</code>
 +
 +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.
 +