diff --git a/.gitignore b/.gitignore index e69de29..40a538b 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +# +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bd81d7..6e5b911 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,6 +202,7 @@ add_subdirectory(python) add_subdirectory(grc) add_subdirectory(apps) add_subdirectory(docs) +add_subdirectory(templates) ######################################################################## # Install cmake search helper for this library diff --git a/README.md b/README.md index f128795..f353b62 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,89 @@ + # gr-verilog +======== + +**GSoC19 project: Cycle-accurate Verilog Design Simulation Integration** + +This is an OOT module for GNU Radio integrating verilog simulation. This module can run Verilog simulation at runtime in GNU Radio based on [Verilator](https://www.veripool.org/wiki/verilator/), an open-source Verilog simulator. + +So far, serveral blocks namely `verilog_axi_ii`, `verilog_axi_ff`, `verilog_axi_ss` and `verilog_axi_cc`, hereinafter referred to as `verilog_axi_xx`, were implemented. + +The `verilog_axi_xx` block can be used in both python code or GNU Radio Companion. + +## Installation + +First you need to install the dependencies (see below). + +Then, you need to download this repository +```bash +$ git clone https://github.com/B0WEN-HU/gr-verilog.git +``` + +After this, gr-verilog should be installed as any other GNU Radio out-of-tree module. +```bash +$ cd gr-verilog +$ mkdir build +$ cd build +$ cmake .. +$ make +$ sudo make install +$ sudo ldconfig +``` +If your GNU Radio is installed in other directory (rather than /usr/local), then replace the cmake line `cmake ..` above with: `cmake -DCMAKE_INSTALL_PREFIX= ..` + +## Dependencies + +gr-verilog requires: + +`GNU Radio` version 3.7.11 or newer. + +`GNU Make` version 4.1 or newer. + +`Verilator` version 3.916 or newer. + +`gcc` version 7.4.0 or newer. + +## Usage + +`verilog_axi_xx` blocks require user's Verilog module to follow [AXI4-stream](https://static.docs.arm.com/ihi0051/a/IHI0051A_amba4_axi4_stream_v1_0_protocol_spec.pdf) input and output interfaces and protocols. If your design does not use AXI4-stream interfaces and protocols, you need to have an additional top Verilog module to wrap it up in order to use `verilog_axi_xx` blocks. The `verilog_axi_xx` blocks use only part of the interfaces of AXI4-stream protocol, which are listed below: + +``` +// These are input and output ports required in the Verilog design + * AXI signals: + * ACLK input + * ARESETn input + * TVALID_IN input + * TREADY_IN output + * TVALID_OUT output + * TREADY_OUT input + * TDATA_IN[31:0] input + * TDATA_OUT[31:0] output +``` + +Once you have a Verilog module with the interfaces required, now you can test your Verilog module in GNU Radio. The easiest way is to use GNU Radio Companion. You should be able to find a block named `Verilog AXI` in GNU Radio Companion if you installed this OOT module correctly. You need to choose the type of the block (usually Int), specify the Verilog file, and leave other options as default. Then, if everything goes well, you can use your Verilog design just like any other blocks in GNU Radio. + +You can also use the `verilog_axi_xx` blocks in python. First you need to import the module: + +```python +import verilog +``` +After that, you need to use following code to instantiate a `verilog_axi_xx` object with parameters wrapped in `"${ }"`. `${type.fcn}` represents the data type of the block `ii` for `Int`, `ff` for `Float`, `ss` for `Short` and `cc` for `Complex`. `${file}` is the filename of the Verilog file, `String` type, it should be an absolute path. `${overwrite}` is `Boolean` type, indicates whether to overwrite the template files in user's Verilog file directory. `${IO_ratio}` is `Float` type, it represents the ratio of number of input and output items, the right parameter can help the scheduler improve the performance. `${verilator_options}` is `String` type, the block passes the options to Verilator. `${skip_output_items}` is `Int` type, the block will skip first `skip_output_items` output items. + +``` +vl = verilog.verilog_verilog_axi_${type.fcn}(${file}, ${overwrite}, ${IO_ratio}, ${verilator_options}, ${module_flag}, ${skip_output_items}) +``` + +## Examples +You can find the example `apps/verilog_axi_ii_demo.grc`. you need to specify the Verilog file for `Verilog AXI` block before running the flow graph. You can use the Verilog file `double_axi.v` in `examples/double/`. `double_axi.v` just take the input and shift 1 bit left (which double the input). Then, you should be able to see the results in the GUI. + +The example `apps/verilog_axi_ff_demo.grc` shows how `Verilog AXI` works with `Float` input and output. You can use a very same Verilog module as above, `double_axi.v`. You can see more obvious effects of what `double_axi.v` does. But how could the same Verilog module be able to deal with both integer and float number? Well, actually there is a pair of functions in the cpp template `templates/axi_module.cpp` named `float_to_fix` and `fix_to_float`, which can automatically convert floating point number and fixed point number. You may need to modify the function in order to fit in certain design. + +## Hint +The `Complex` type of `Verilog AXI`, `verilog_axi_cc`, is not the block that is ready to use, you definitely will not use only 32 bits to represent a complex number, so you have to some do modifications on the template file in order to fit in your design. Please define the `_USER_MODIFIED_` macro to avoid unnecessary code being compiled (because if you changed the interfaces, there will be a lot of syntax errors in the existing template code). -GSoC project: Cycle-accurate Verilog Design Simulation Integration +## Future Work +Add some image to README.md -This is an OOT module for GNU Radio integrating verilog simultion. +Add more examples. +Bring verilog_general_xx into the module. \ No newline at end of file diff --git a/apps/verilog_axi_ff_demo.grc b/apps/verilog_axi_ff_demo.grc new file mode 100644 index 0000000..7c4970b --- /dev/null +++ b/apps/verilog_axi_ff_demo.grc @@ -0,0 +1,626 @@ + + + + Thu Aug 22 16:50:22 2019 + + options + + author + Bowen Hu + + + window_size + + + + category + [GRC Hier Blocks] + + + comment + + + + description + This is a demo of verilog_axi_ff block + + + _enabled + True + + + _coordinate + (8, 8) + + + _rotation + 0 + + + generate_options + qt_gui + + + hier_block_src_path + .: + + + id + verilog_axi_ff_demo + + + max_nouts + 0 + + + qt_qss_theme + + + + realtime_scheduling + + + + run_command + {python} -u {filename} + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + verilog_axi_ii demo + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 132) + + + _rotation + 0 + + + id + samp_rate + + + value + 32000 + + + + analog_sig_source_x + + amp + 1 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + freq + 1000 + + + _coordinate + (288, 260) + + + _rotation + 0 + + + id + analog_sig_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + offset + 0 + + + type + float + + + samp_rate + samp_rate + + + waveform + analog.GR_COS_WAVE + + + + qtgui_time_sink_x + + autoscale + False + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + False + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (920, 292) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_time_sink_x_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + Before Verilog AXI + + + marker1 + -1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + After Verilog AXI + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "" + + + nconnections + 2 + + + size + 1024 + + + srate + samp_rate + + + stemplot + False + + + tr_chan + 0 + + + tr_delay + 0 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_FREE + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "" + + + type + float + + + update_time + 0.10 + + + ylabel + Amplitude + + + yunit + "" + + + ymax + 4 + + + ymin + -4 + + + + verilog_axi_xx + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (584, 444) + + + _rotation + 0 + + + id + verilog_axi_xx_0 + + + IO_ratio + 1.0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + module_flag + 0 + + + overwrite + True + + + skip_output_items + 0 + + + verilator_options + + + + file + + + + + analog_sig_source_x_0 + qtgui_time_sink_x_0 + 0 + 0 + + + analog_sig_source_x_0 + verilog_axi_xx_0 + 0 + 0 + + + verilog_axi_xx_0 + qtgui_time_sink_x_0 + 0 + 1 + + diff --git a/apps/verilog_axi_ii_demo.grc b/apps/verilog_axi_ii_demo.grc new file mode 100644 index 0000000..d8cf35f --- /dev/null +++ b/apps/verilog_axi_ii_demo.grc @@ -0,0 +1,1095 @@ + + + + Thu Aug 22 14:47:29 2019 + + options + + author + Bowen Hu + + + window_size + + + + category + [GRC Hier Blocks] + + + comment + + + + description + This is a demo of verilog_axi_ii block + + + _enabled + True + + + _coordinate + (8, 8) + + + _rotation + 0 + + + generate_options + qt_gui + + + hier_block_src_path + .: + + + id + verilog_axi_ii_demo + + + max_nouts + 0 + + + qt_qss_theme + + + + realtime_scheduling + + + + run_command + {python} -u {filename} + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + verilog_axi_ii demo + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 132) + + + _rotation + 0 + + + id + samp_rate + + + value + 32000 + + + + analog_fastnoise_source_x + + amp + 32 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (216, 268) + + + _rotation + 0 + + + id + analog_fastnoise_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + noise_type + analog.GR_GAUSSIAN + + + type + int + + + seed + 0 + + + samples + 8192 + + + + blocks_int_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (760, 292) + + + _rotation + 0 + + + id + blocks_int_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 1 + + + vlen + 1 + + + + blocks_int_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (760, 484) + + + _rotation + 0 + + + id + blocks_int_to_float_1 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 1 + + + vlen + 1 + + + + qtgui_time_sink_x + + autoscale + False + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + False + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (936, 460) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_time_sink_x_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + + + + marker1 + -1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "After Verilog AXI" + + + nconnections + 1 + + + size + 1024 + + + srate + samp_rate + + + stemplot + False + + + tr_chan + 0 + + + tr_delay + 0 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_FREE + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "" + + + type + float + + + update_time + 0.10 + + + ylabel + Amplitude + + + yunit + "" + + + ymax + 256 + + + ymin + -256 + + + + qtgui_time_sink_x + + autoscale + False + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + False + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (936, 268) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_time_sink_x_1 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + + + + marker1 + -1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "Before Verilog AXI" + + + nconnections + 1 + + + size + 1024 + + + srate + samp_rate + + + stemplot + False + + + tr_chan + 0 + + + tr_delay + 0 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_FREE + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "" + + + type + float + + + update_time + 0.10 + + + ylabel + Amplitude + + + yunit + "" + + + ymax + 256 + + + ymin + -256 + + + + verilog_axi_xx + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (512, 444) + + + _rotation + 0 + + + id + verilog_axi_xx_0 + + + IO_ratio + 1.0 + + + type + int + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + module_flag + 0 + + + overwrite + True + + + skip_output_items + 0 + + + verilator_options + + + + file + + + + + analog_fastnoise_source_x_0 + blocks_int_to_float_0 + 0 + 0 + + + analog_fastnoise_source_x_0 + verilog_axi_xx_0 + 0 + 0 + + + blocks_int_to_float_0 + qtgui_time_sink_x_1 + 0 + 0 + + + blocks_int_to_float_1 + qtgui_time_sink_x_0 + 0 + 0 + + + verilog_axi_xx_0 + blocks_int_to_float_1 + 0 + 0 + + diff --git a/examples/double/double.v b/examples/double/double.v new file mode 100644 index 0000000..7f54774 --- /dev/null +++ b/examples/double/double.v @@ -0,0 +1,10 @@ +module double( + input clock, + input reset, + input [31:0] io_in, + output [31:0] io_out +); + // wire [32:0] temp; + // assign temp = 32'b1 + io_in; + assign io_out = io_in << 1;//temp[31:0]; +endmodule \ No newline at end of file diff --git a/examples/double/double_axi.v b/examples/double/double_axi.v new file mode 100644 index 0000000..9998b35 --- /dev/null +++ b/examples/double/double_axi.v @@ -0,0 +1,22 @@ +module double_axi( + input ACLK, + input ARESETn, + output TREADY_IN, + input TVALID_IN, + input [31:0] TDATA_IN, + input TREADY_OUT, + output TVALID_OUT, + output [31:0] TDATA_OUT +); + +double DUT( + .clock(ACLK), + .reset(ARESETn), + .io_in(TDATA_IN), + .io_out(TDATA_OUT) +); + +assign TREADY_IN = 1'b1; +assign TVALID_OUT = 1'b1; + +endmodule \ No newline at end of file diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index d776de7..9277544 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -18,5 +18,6 @@ # Boston, MA 02110-1301, USA. install(FILES - DESTINATION share/gnuradio/grc/blocks + verilog_verilog_axi_xx.xml DESTINATION share/gnuradio/grc/blocks + # verilog_verilog_axi.yml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/verilog_verilog_axi_xx.xml b/grc/verilog_verilog_axi_xx.xml new file mode 100644 index 0000000..d621ab5 --- /dev/null +++ b/grc/verilog_verilog_axi_xx.xml @@ -0,0 +1,84 @@ + + Verilog AXI + verilog_axi_xx + [Verilog] + import verilog + verilog.verilog_axi_$(type.fcn)($file, $overwrite, $IO_ratio, $verilator_options, $module_flag, $skip_output_items) + + Verilog File + file + + file_open + + + IO Type + type + enum + + + + + + + Overwrite + overwrite + False + enum + + + + + IO Ratio + IO_ratio + 1.0 + float + + + Verilator Options + verilator_options + + string + + + Module Flag + module_flag + 0 + int + + + Skip Output + skip_output_items + 0 + int + + + in + $type + + + out + $type + + diff --git a/grc/verilog_verilog_axi_xx.yml b/grc/verilog_verilog_axi_xx.yml new file mode 100644 index 0000000..1b4b7aa --- /dev/null +++ b/grc/verilog_verilog_axi_xx.yml @@ -0,0 +1,52 @@ +id: verilog_verilog_axi_xx +label: Verilog AXI +flags: [ python, cpp ] + +parameters: +- id: file + label: Verilog File + dtype: file_open +- id: type + label: IO Type + dtype: enum + options: [complex, float, int, short] + option_attributes: + fcn: [cc, ff, ii, ss] + hide: part +- id: overwrite + label: Overwrite + dtype: enum + default: 'False' + options: ['True', 'False'] + option_labels: ['Yes', 'No'] +- id: IO_ratio + label: IO Ratio + dtype: real + default: '1.0' +- id: verilator_options + label: Verilator Options + dtype: string + default: '""' +- id: module_flag + label: Module Flag + dtype: int + default: '0' +- id: skip_output_items + label: Skip Output + dtype: int + default: '0' + +inputs: +- domain: stream + dtype: ${ type } + +outputs: +- domain: stream + dtype: ${ type } + +templates: + imports: import verilog + make: verilog.verilog_verilog_axi_${type.fcn}(${file}, ${overwrite}, ${IO_ratio}, ${verilator_options}, ${module_flag}, ${skip_output_items}) + + +file_format: 1 diff --git a/include/verilog/CMakeLists.txt b/include/verilog/CMakeLists.txt index ac76e90..17b3305 100644 --- a/include/verilog/CMakeLists.txt +++ b/include/verilog/CMakeLists.txt @@ -22,5 +22,8 @@ ######################################################################## install(FILES api.h - DESTINATION include/verilog + verilog_axi_ii.h + verilog_axi_ff.h + verilog_axi_ss.h + verilog_axi_cc.h DESTINATION include/verilog ) diff --git a/include/verilog/Shared_lib.h b/include/verilog/Shared_lib.h new file mode 100644 index 0000000..7985966 --- /dev/null +++ b/include/verilog/Shared_lib.h @@ -0,0 +1,81 @@ + +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_SHARED_LIB_H +#define INCLUDED_VERILOG_SHARED_LIB_H + +#include +#include + +namespace gr { + namespace verilog { + + typedef void (*func_ptr)(void); + +#ifdef __linux + class Shared_lib + { + private: + // Private members + + // The path and name of the library + std::string lib_name; + std::string lib_path; + + // The hanle of the shared library + void *lib_handle; + + // The status of the shared library + enum {LIB_NULL, LIB_LOAD_FAILURE, LIB_LOAD_SUCCESS} lib_status; + + public: + // Public members + + Shared_lib(); + ~Shared_lib(); + + // The function that load the shared library + // It will return -1 when there is any error + // It will return 0 if the shared library was loaded successfully + int load_lib(const char *ext_lib_path, const char *ext_lib_name); + + // The function that find the function in the library + // It will return NULL when it cannot find the function + // It will return the pointer of the function + func_ptr find_func(const char *func_name) const; + + // The function that close the library + void close_lib(void); + + // DEBUG + std::string get_lib_path() const; + std::string get_lib_name() const; + std::string get_lib_status() const; + void * get_lib_handle() const; + + }; +#endif + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_SHARED_LIB_H */ + diff --git a/include/verilog/Shell_cmd.h b/include/verilog/Shell_cmd.h new file mode 100644 index 0000000..5ef4467 --- /dev/null +++ b/include/verilog/Shell_cmd.h @@ -0,0 +1,67 @@ + +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_SHELL_CMD_H +#define INCLUDED_VERILOG_SHELL_CMD_H + +#include +#include +#include + +namespace gr { + namespace verilog { + +#ifdef __linux + class Shell_cmd + { + private: + // Private members + + // The the shell message of the latest call + std::vector msgvec; + + public: + // Public members + + Shell_cmd(); + ~Shell_cmd(); + + // The exec() function of the class + // It will return -1 when there is any error + // It will return the line number of message if exit normally + int exec(const char *cmd); + + // The get_msg() function of the class + // It will return msg (i-th line, from 0) + std::string get_msg(unsigned int i); + + // The print_msg() function + // It print out the message that stored in msgvec + void print_msg(std::ostream &out); + + }; +#endif + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_SHELL_CMD_H */ + diff --git a/include/verilog/constants.h b/include/verilog/constants.h new file mode 100644 index 0000000..8989101 --- /dev/null +++ b/include/verilog/constants.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_VERILOG_CONSTANTS_H +#define INCLUDED_GR_VERILOG_CONSTANTS_H + +#include +#include + +namespace gr { + namespace verilog { + VERILOG_API const std::string datadir(); + VERILOG_API std::string templatedir(); + } /* namespace verilog */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_VERILOG_CONSTANTS_H */ diff --git a/include/verilog/gr_verilog_iotype.h b/include/verilog/gr_verilog_iotype.h new file mode 100644 index 0000000..85399a2 --- /dev/null +++ b/include/verilog/gr_verilog_iotype.h @@ -0,0 +1,32 @@ + +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_IOTYPE_H +#define INCLUDED_VERILOG_IOTYPE_H + +namespace gr { + namespace verilog { + + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_IOTYPE_H */ diff --git a/include/verilog/verilog_axi_cc.h b/include/verilog/verilog_axi_cc.h new file mode 100644 index 0000000..ef26fd5 --- /dev/null +++ b/include/verilog/verilog_axi_cc.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_CC_H +#define INCLUDED_VERILOG_VERILOG_AXI_CC_H + +#include +#include + +namespace gr { + namespace verilog { + + /*! + * \brief <+description of block+> + * \ingroup verilog + * + */ + class VERILOG_API verilog_axi_cc : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of verilog::verilog_axi_cc. + * + * To avoid accidental use of raw pointers, verilog::verilog_axi_cc's + * constructor is in a private implementation + * class. verilog::verilog_axi_cc::make is the public interface for + * creating new instances. + */ + static sptr make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_CC_H */ + diff --git a/include/verilog/verilog_axi_ff.h b/include/verilog/verilog_axi_ff.h new file mode 100644 index 0000000..275a695 --- /dev/null +++ b/include/verilog/verilog_axi_ff.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_FF_H +#define INCLUDED_VERILOG_VERILOG_AXI_FF_H + +#include +#include + +namespace gr { + namespace verilog { + + /*! + * \brief <+description of block+> + * \ingroup verilog + * + */ + class VERILOG_API verilog_axi_ff : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of verilog::verilog_axi_ff. + * + * To avoid accidental use of raw pointers, verilog::verilog_axi_ff's + * constructor is in a private implementation + * class. verilog::verilog_axi_ff::make is the public interface for + * creating new instances. + */ + static sptr make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_FF_H */ + diff --git a/include/verilog/verilog_axi_ii.h b/include/verilog/verilog_axi_ii.h new file mode 100644 index 0000000..68d0998 --- /dev/null +++ b/include/verilog/verilog_axi_ii.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_II_H +#define INCLUDED_VERILOG_VERILOG_AXI_II_H + +#include +#include + +namespace gr { + namespace verilog { + + /*! + * \brief <+description of block+> + * \ingroup verilog + * + */ + class VERILOG_API verilog_axi_ii : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of verilog::verilog_axi_ii. + * + * To avoid accidental use of raw pointers, verilog::verilog_axi_ii's + * constructor is in a private implementation + * class. verilog::verilog_axi_ii::make is the public interface for + * creating new instances. + */ + static sptr make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_II_H */ + diff --git a/include/verilog/verilog_axi_ss.h b/include/verilog/verilog_axi_ss.h new file mode 100644 index 0000000..7e259f2 --- /dev/null +++ b/include/verilog/verilog_axi_ss.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_SS_H +#define INCLUDED_VERILOG_VERILOG_AXI_SS_H + +#include +#include + +namespace gr { + namespace verilog { + + /*! + * \brief <+description of block+> + * \ingroup verilog + * + */ + class VERILOG_API verilog_axi_ss : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of verilog::verilog_axi_ss. + * + * To avoid accidental use of raw pointers, verilog::verilog_axi_ss's + * constructor is in a private implementation + * class. verilog::verilog_axi_ss::make is the public interface for + * creating new instances. + */ + static sptr make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_SS_H */ + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 26a4a95..f450c5f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -26,6 +26,14 @@ include_directories(${Boost_INCLUDE_DIR}) link_directories(${Boost_LIBRARY_DIRS}) list(APPEND verilog_sources + ${CMAKE_CURRENT_BINARY_DIR}/constants.cc + verilog_axi_ii_impl.cc + + Shell_cmd.cpp + Shared_lib.cpp + verilog_axi_ff_impl.cc + verilog_axi_ss_impl.cc + verilog_axi_cc_impl.cc ) set(verilog_sources "${verilog_sources}" PARENT_SCOPE) @@ -80,3 +88,12 @@ GR_ADD_TEST(test_verilog test-verilog) message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Building for version: ${VERSION} / ${LIBVER}") +######################################################################## +# Configure templates +######################################################################## +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/constants.cc.in + ${CMAKE_CURRENT_BINARY_DIR}/constants.cc + ESCAPE_QUOTES + @ONLY +) diff --git a/lib/Shared_lib.cpp b/lib/Shared_lib.cpp new file mode 100644 index 0000000..dd64e27 --- /dev/null +++ b/lib/Shared_lib.cpp @@ -0,0 +1,137 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "verilog/Shared_lib.h" + +#define SLASH '/' +#define _EXIT_FAILURE -1 +#define _EXIT_SUCCESS 0 + +namespace gr { + namespace verilog { + + // The constructor + Shared_lib::Shared_lib() + : lib_handle(NULL), lib_status(LIB_NULL), + lib_path(""), lib_name("") + {} + + // The destructor + Shared_lib::~Shared_lib() { + if(LIB_LOAD_SUCCESS == this->lib_status) + this->close_lib(); + } + + // The load_lib function of the class + int Shared_lib::load_lib(const char *ext_lib_path, const char *ext_lib_name) + { + // Get the the fullname of the shared library + std::string lib_fullname = ext_lib_path; + // Check the slash at the end of the path + if (SLASH == lib_fullname.back()) { + this->lib_path = lib_fullname; + this->lib_name = ext_lib_name; + + lib_fullname += ext_lib_name; + } + else { + lib_fullname += SLASH; + + this->lib_path = lib_fullname; + this->lib_name = ext_lib_name; + + lib_fullname += ext_lib_name; + } + + + // Open the shared library + this->lib_handle = dlopen(lib_fullname.c_str(), RTLD_LAZY); + // If the library was not loaded + if (NULL == this->lib_handle) { + this->lib_status = LIB_LOAD_FAILURE; + return _EXIT_FAILURE; + } + + // Otherwise the library was loaded successfully + this->lib_status = LIB_LOAD_SUCCESS; + return _EXIT_SUCCESS; + } + + // The find_func function of the class + func_ptr Shared_lib::find_func(const char *func_name) const + { + func_ptr func_tmp; + func_tmp = (func_ptr)dlsym(this->lib_handle, func_name); + // If the function was not found + if (NULL == func_tmp) { + // TODO: throw error + return NULL; + } + // Otherwise + return func_tmp; + } + + // The close_lib function of the class + void Shared_lib::close_lib(void) + { + dlclose(this->lib_handle); + + this->lib_path = ""; + this->lib_name = ""; + this->lib_handle = NULL; + this->lib_status = LIB_NULL; + return ; + } + + // DEBUG + std::string Shared_lib::get_lib_path() const + { + return this->lib_path; + } + std::string Shared_lib::get_lib_name() const + { + return this->lib_name; + } + std::string Shared_lib::get_lib_status() const + { + switch (this->lib_status) { + case LIB_NULL: + return std::string("LIB_NULL"); + case LIB_LOAD_FAILURE: + return std::string("LIB_LOAD_FAILURE"); + case LIB_LOAD_SUCCESS: + return std::string("LIB_LOAD_SUCCESS"); + default: + return std::string("ERROR"); + } + return std::string("ERROR"); + } + void * Shared_lib::get_lib_handle() const + { + return this->lib_handle; + } + + } /* namespace verilog */ +} /* namespace gr */ + diff --git a/lib/Shell_cmd.cpp b/lib/Shell_cmd.cpp new file mode 100644 index 0000000..28aa3e9 --- /dev/null +++ b/lib/Shell_cmd.cpp @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include "verilog/Shell_cmd.h" + +#define BUFFER_SIZE 1024 +#define _EXIT_FAILURE -1 + +namespace gr { + namespace verilog { + + // The constructor + Shell_cmd::Shell_cmd() { + this->msgvec.clear(); + } + + // The destructor + Shell_cmd::~Shell_cmd() { + this->msgvec.clear(); + } + + // The exec() function of the class + int Shell_cmd::exec(const char *cmd) + { + this->msgvec.clear(); + // Set up the pipe + FILE *pipe_ptr = popen(cmd, "r"); + if (!pipe_ptr) { + return _EXIT_FAILURE; + } + + // Read from the pipe_ptr + char buf[BUFFER_SIZE]; + while (NULL != fgets(buf, sizeof(buf), pipe_ptr)) { + if ('\n' == buf[strlen(buf) - 1]) { + // Remove the '\n' + buf[strlen(buf) - 1] = '\0'; + } + this->msgvec.push_back(std::string(buf)); + } + + // Close the pipe + pclose(pipe_ptr); + + // Return the line number + return this->msgvec.size(); + } + + // The get_msg() function + std::string Shell_cmd::get_msg(unsigned int i) + { + if (msgvec.size() < (i + 1)) + return ""; + else + return msgvec[i]; + } + + + // The print_msg(std::ostream &out) function + void Shell_cmd::print_msg(std::ostream &out) + { + for (int i = 0; i < this->msgvec.size(); ++i) + { + out << (this->msgvec[i]) << std::endl; + } + } + + + } /* namespace verilog */ +} /* namespace gr */ + diff --git a/lib/constants.cc.in b/lib/constants.cc.in new file mode 100644 index 0000000..98d8374 --- /dev/null +++ b/lib/constants.cc.in @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "verilog/constants.h" +#include + +namespace gr { + namespace verilog { + const std::string + datadir() { + return "@CMAKE_INSTALL_PREFIX@/@GR_PKG_DATA_DIR@/templates/"; + } + + std::string + templatedir() { + + return gr::prefs().get_string("verilog", + "templatedir", + datadir()); + + } + } +} //namespace gr::verilog diff --git a/lib/verilog_axi_cc_impl.cc b/lib/verilog_axi_cc_impl.cc new file mode 100644 index 0000000..7b83bb7 --- /dev/null +++ b/lib/verilog_axi_cc_impl.cc @@ -0,0 +1,444 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "verilog_axi_cc_impl.h" +#include +#include +#include +#include + + +#include "verilog/constants.h" + +#include "verilog/Shell_cmd.h" +#include "verilog/Shared_lib.h" + +#define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" +#define CPP_TEMPLATE_NAME "axi_module.cpp" +#define HEADER_TEMPLATE_NAME "axi_module.h" +#define SHARED_LIB_NAME "lib_axi_module.so" +#define M_dir "obj_dir" + +#define MAKEFILE_TEMPLATE_PATH templatedir() +#define CPP_TEMPLATE_PATH templatedir() + +#define _EXIT_SUCCESS 0 +#define _EXIT_FAILURE -1 + +namespace gr { + namespace verilog { + + verilog_axi_cc::sptr + verilog_axi_cc::make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, unsigned int skip_output_items) + { + return gnuradio::get_initial_sptr + (new verilog_axi_cc_impl(filename, overwrite, IO_ratio, + verilator_options, module_flag, skip_output_items)); + } + + /* + * The private constructor + */ + verilog_axi_cc_impl::verilog_axi_cc_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items) + : gr::block("verilog_axi_cc", + gr::io_signature::make(1, 1, sizeof(ITYPE)), + gr::io_signature::make(1, 1, sizeof(OTYPE))) + { + /* Get module_name and module_path */ + std::string filename_temp(filename); + std::size_t filename_pos = filename_temp.rfind(SLASH); + if (std::string::npos == filename_pos) { + GR_LOG_WARN(d_logger, "filename error"); + } + + this->verilog_module_name = filename_temp.substr(filename_pos + 1); + this->verilog_module_path = filename_temp.substr(0, filename_pos + 1); + + // Test access + this->test_access(filename, + (std::string("\ncan't access verilog file in: ") + + this->verilog_module_path).c_str()); + + /* Initialize makefile_template_path and cpp_template_path */ + this->makefile_template_path = MAKEFILE_TEMPLATE_PATH; + this->cpp_template_path = CPP_TEMPLATE_PATH; + // Test access + this->test_access((this->makefile_template_path + AXI_MODULE_CL_MAKEFILE).c_str(), + (std::string("\ncan't access makefile template in: ") + + this->makefile_template_path).c_str()); + this->test_access((this->cpp_template_path + CPP_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access cpp template in: ") + + this->cpp_template_path).c_str()); + this->test_access((this->cpp_template_path + HEADER_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access header template in: ") + + this->cpp_template_path).c_str()); + + // Reset the initial time + this->main_time = 0; + + // Initial skip_output_items + this->skip_output_items = skip_output_items; + + // Set overwrite + this->overwrite = overwrite; + + // Set IO_ratio + this->IO_ratio = IO_ratio; + + // Set verilator options + this->verilator_options = std::string(verilator_options); + + // Set module_flag + this->module_flag = module_flag; + + /* Call Verilator (Makefile) to generate the cpp code */ + // There will be a Shell_cmd object created in the function to + // run configure.sh + // configure.sh will copy the makefile template and modify it + // for the verilog module + // the Shell_cmd will run make at the verilog module path + + // Check enviroments : make, g++, verilator + this->check_env("make", "can't find make"); + this->check_env("g++", "can't find g++"); + this->check_env("verilator", "can't find verilator"); + + //try { + // this->generate_verilator_file(); + //} catch (...) { + // + //} + + /* Generate shared library and initialize verilog_module_so */ + // There will be a Shell_cmd object created in the function to + // run make at the verilog module path + // ! generate_verilator_file will be included in the this->generate_so() + try { + // obtain exclusive access for duration of generate_so() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->generate_so(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Load the shared library that generated above */ + // The function should also initialize the external veriable + // in the shred library + // Call verilog_module_so.find_func(VERILOG_INIT_FUNC) + // Call verilog_module_so.find_func(VERILOG_RESET_FUNC) + // shared library function reset() should be defalt generated + // There would be a function called general_sim() + // general_sim() could accept input and output of all port with + // the help of port map stored in the verilog_data + try { + // obtain exclusive access for duration of load_lib() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->load_lib(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Initialize sim */ + this->sim = NULL; + } + + /* + * Our virtual destructor. + */ + verilog_axi_cc_impl::~verilog_axi_cc_impl() + { + // There should not be any errors in destructor + typedef void (*Close_func) (void); + Close_func axi_close; + axi_close = + (Close_func)this->verilog_module_so.find_func("AXI_close"); + if (axi_close != NULL) + axi_close(); + + this->release_lib(); + } + + void + verilog_axi_cc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ + ninput_items_required[0] = (int) round(IO_ratio * noutput_items); + } + + int + verilog_axi_cc_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const ITYPE *in = (const ITYPE *) input_items[0]; + OTYPE *out = (OTYPE *) output_items[0]; + + // Initial and Reset the module + if (NULL == this->sim) + { + typedef void (*Initial_func) (void); + typedef void (*Reset_func) (unsigned int flag); + + Initial_func axi_init; + Reset_func axi_reset; + + axi_init = + (Initial_func)this->verilog_module_so.find_func("AXI_init"); + axi_reset = + (Reset_func)this->verilog_module_so.find_func("AXI_reset"); + + if ((NULL == axi_init) or (NULL == axi_reset)) { + throw std::runtime_error("can't find correct AXI_init or AXI_reset in shared library"); + return _EXIT_FAILURE; + } + + axi_init(); + axi_reset(this->module_flag); + + this->sim = + (Simulation_func)this->verilog_module_so.find_func("AXI_async_transfer_cc"); + + if (NULL == this->sim) { + throw std::runtime_error("can't find correct AXI_async_transfer_cc in shared library"); + return _EXIT_FAILURE; + } + } + + + // Do <+signal processing+> + unsigned int input_i; + unsigned int output_i; + for (input_i = 0, output_i = 0; output_i < noutput_items && input_i < ninput_items[0];) + { + unsigned char status_code; + + try { + status_code = + this->sim(in[input_i], out[output_i], this->main_time); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + // input + if (status_code & (1 << 1)) { + ++input_i; + } + // output + if (status_code & 1) { + if (this->skip_output_items > 0) + --this->skip_output_items; + else + ++output_i; + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (input_i); + + // Tell runtime system how many output items we produced. + return output_i; + } + + + /* gr::verilog::verilog_axi_cc private member functions */ + + int + verilog_axi_cc_impl::generate_so() + { + // const char + const std::string ENTER = "\n"; + const std::string BACKSLASH = "\\"; + + // compile and link error code + int cl_err_code = 0; + + // Shell_cmd class + Shell_cmd bash; + std::string cmd = ""; + + // $ cd ${verilog_module_path} + cmd += "cd "; + cmd += this->verilog_module_path; + cmd += ENTER; + + // $ cp ${makefile_template_path}/axi_module_cl.mk ${verilog_module_path} + // #define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" + cmd += "cp "; + if (!this->overwrite) + cmd += "-n"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->makefile_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->makefile_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + /* alternative solution: + if (this->overwrite) { + cmd += "cp"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + else { + std::string CL_makefile_user_filename = + (this->verilog_module_path + AXI_MODULE_CL_MAKEFILE); + std::string CPP_user_filename = + (this->verilog_module_path + CPP_TEMPLATE_NAME).c_str(); + + bool CL_makefile_flag = this->test_access(CL_makefile_user_filename.c_str(), ""); + bool CPP_flag = this->test_access(CPP_user_filename.c_str(), ""); + + if (!CL_makefile_flag || !CPP_flag) { + cmd += "cp "; + + if (!CL_makefile_flag) + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + + if (!CPP_flag) { + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + } + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + } */ + + + // $ make -j -f axi_module_cl.mk \ + // USER_VL_FILENAME=user_module_name.v \ + // USER_CPP_FILENAME=axi_module.cpp \ + // M_DIR=obj_dir + cmd += std::string("") + "make -j -f " + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + "USER_VL_FILENAME=" + this->verilog_module_name; + cmd += std::string(" ") + "USER_CPP_FILENAME=" + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + " M_DIR=" + M_dir; + // cmd += verilator_options: + cmd += std::string(" ") + "VERILATOR_OPTIONS=" + this->verilator_options; + cmd += ENTER; + + cmd += ENTER; + + try { + cl_err_code = bash.exec(cmd.c_str()); + if (cl_err_code == _EXIT_FAILURE) { + throw std::runtime_error("Shell_cmd execute error"); + } + + // Output the message + // bash.print_msg(std::cout); + } + catch (...) { + bash.print_msg(std::cerr); + throw; + } + + return cl_err_code; + } + + int + verilog_axi_cc_impl::load_lib() + { + int lib_err_code; + lib_err_code = + this->verilog_module_so.load_lib((this->verilog_module_path + M_dir).c_str(), + SHARED_LIB_NAME); + if (lib_err_code == _EXIT_FAILURE) { + throw std::runtime_error("can't load shared library"); + } + + return lib_err_code; + } + + int + verilog_axi_cc_impl::release_lib() + { + this->verilog_module_so.close_lib(); + } + + bool + verilog_axi_cc_impl::test_access(const char *filepath, const char *err_msg = "") + { + + if ( access(filepath, R_OK) == _EXIT_FAILURE ) { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % filepath + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + bool + verilog_axi_cc_impl::check_env(const char *package, const char *err_msg = "") + { + + Shell_cmd bash; + bash.exec((std::string("which ") + package).c_str()); + if (bash.get_msg(0) == "") { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % package + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + /* gr::verilog::verilog_axi_cc private member functions */ + + } /* namespace verilog */ +} /* namespace gr */ + diff --git a/lib/verilog_axi_cc_impl.h b/lib/verilog_axi_cc_impl.h new file mode 100644 index 0000000..0de610f --- /dev/null +++ b/lib/verilog_axi_cc_impl.h @@ -0,0 +1,138 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_CC_IMPL_H +#define INCLUDED_VERILOG_VERILOG_AXI_CC_IMPL_H + +#include +#include + +#include "verilog/Shared_lib.h" + +#define SLASH "/" + +namespace gr { + namespace verilog { + + class verilog_axi_cc_impl : public verilog_axi_cc + { + private: + /* gr::verilog::verilog_axi_cc private member variables */ + typedef gr_complex ITYPE; + typedef gr_complex OTYPE; + + // The path and name of user's verilog module + // Construct by (const char *filename) + std::string verilog_module_path; + std::string verilog_module_name; + + // The path of makefile template + std::string makefile_template_path; + + // The path of cpp template + std::string cpp_template_path; + + // The class that control the shared library + // Use verilog_module_so.load_lib(std::string verilog_module_path, std::string lib_name) to load library + // Use verilog_module_so.find_func(std::string func_name) to get the function + // Use verilog_module_so.release_lib(std::string string lib_name) to release the library + Shared_lib verilog_module_so; + + // typedef void (*Simulation_func) + typedef unsigned char (*Simulation_func) (const ITYPE &verilog_input, const OTYPE &verilog_ouput, const unsigned int &main_time); + Simulation_func sim; + + + unsigned int main_time; + + unsigned int skip_output_items; + + // overwrite user templates in the path + bool overwrite; + + // used for forecast + float IO_ratio; + + // thread safe + boost::mutex vl_mutex; + + std::string verilator_options; + + // the parameter send to the template cpp code in function reset(unsiged int) + // user can make use of it + unsigned int module_flag; + + /* gr::verilog::verilog_axi_cc private member variables */ + + + /* gr::verilog::verilog_axi_cc private member functions */ + + /* Construct routine */ + // The function that call Verilator (Makefile) to generate the cpp code + //int generate_verilator_file() throw(std::runtime_error); + + /* + // Parse the Verilator generate file and extract the port map + // The port map should be stored in Veriloag_data verilog_data + int init_port_map() throw(std::logic_error); + */ + + // The function that call g++ (Makefile) to generate the shared library + // There might be some modifications on the tempalte cpp interface file + // ! generate_verilator_file will be included in the this->generate_so() + int generate_so(); + + // The function that load the shared library that generated above + // with the Shared_lib verilog_module_so + int load_lib(); + /* Construct routine */ + + /* Destruct routine */ + + int release_lib(); + + /* Destruct routine */ + + bool test_access(const char *filepath, const char *err_msg); + + bool check_env(const char *package, const char *err_msg); + + /* gr::verilog::verilog_axi_cc private member functions */ + + public: + verilog_axi_cc_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + ~verilog_axi_cc_impl(); + + // Where all the action really happens + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_CC_IMPL_H */ + diff --git a/lib/verilog_axi_ff_impl.cc b/lib/verilog_axi_ff_impl.cc new file mode 100644 index 0000000..3522703 --- /dev/null +++ b/lib/verilog_axi_ff_impl.cc @@ -0,0 +1,444 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "verilog_axi_ff_impl.h" +#include +#include +#include +#include + + +#include "verilog/constants.h" + +#include "verilog/Shell_cmd.h" +#include "verilog/Shared_lib.h" + +#define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" +#define CPP_TEMPLATE_NAME "axi_module.cpp" +#define HEADER_TEMPLATE_NAME "axi_module.h" +#define SHARED_LIB_NAME "lib_axi_module.so" +#define M_dir "obj_dir" + +#define MAKEFILE_TEMPLATE_PATH templatedir() +#define CPP_TEMPLATE_PATH templatedir() + +#define _EXIT_SUCCESS 0 +#define _EXIT_FAILURE -1 + +namespace gr { + namespace verilog { + + verilog_axi_ff::sptr + verilog_axi_ff::make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, unsigned int skip_output_items) + { + return gnuradio::get_initial_sptr + (new verilog_axi_ff_impl(filename, overwrite, IO_ratio, + verilator_options, module_flag, skip_output_items)); + } + + /* + * The private constructor + */ + verilog_axi_ff_impl::verilog_axi_ff_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items) + : gr::block("verilog_axi_ff", + gr::io_signature::make(1, 1, sizeof(ITYPE)), + gr::io_signature::make(1, 1, sizeof(OTYPE))) + { + /* Get module_name and module_path */ + std::string filename_temp(filename); + std::size_t filename_pos = filename_temp.rfind(SLASH); + if (std::string::npos == filename_pos) { + GR_LOG_WARN(d_logger, "filename error"); + } + + this->verilog_module_name = filename_temp.substr(filename_pos + 1); + this->verilog_module_path = filename_temp.substr(0, filename_pos + 1); + + // Test access + this->test_access(filename, + (std::string("\ncan't access verilog file in: ") + + this->verilog_module_path).c_str()); + + /* Initialize makefile_template_path and cpp_template_path */ + this->makefile_template_path = MAKEFILE_TEMPLATE_PATH; + this->cpp_template_path = CPP_TEMPLATE_PATH; + // Test access + this->test_access((this->makefile_template_path + AXI_MODULE_CL_MAKEFILE).c_str(), + (std::string("\ncan't access makefile template in: ") + + this->makefile_template_path).c_str()); + this->test_access((this->cpp_template_path + CPP_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access cpp template in: ") + + this->cpp_template_path).c_str()); + this->test_access((this->cpp_template_path + HEADER_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access header template in: ") + + this->cpp_template_path).c_str()); + + // Reset the initial time + this->main_time = 0; + + // Initial skip_output_items + this->skip_output_items = skip_output_items; + + // Set overwrite + this->overwrite = overwrite; + + // Set IO_ratio + this->IO_ratio = IO_ratio; + + // Set verilator options + this->verilator_options = std::string(verilator_options); + + // Set module_flag + this->module_flag = module_flag; + + /* Call Verilator (Makefile) to generate the cpp code */ + // There will be a Shell_cmd object created in the function to + // run configure.sh + // configure.sh will copy the makefile template and modify it + // for the verilog module + // the Shell_cmd will run make at the verilog module path + + // Check enviroments : make, g++, verilator + this->check_env("make", "can't find make"); + this->check_env("g++", "can't find g++"); + this->check_env("verilator", "can't find verilator"); + + //try { + // this->generate_verilator_file(); + //} catch (...) { + // + //} + + /* Generate shared library and initialize verilog_module_so */ + // There will be a Shell_cmd object created in the function to + // run make at the verilog module path + // ! generate_verilator_file will be included in the this->generate_so() + try { + // obtain exclusive access for duration of generate_so() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->generate_so(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Load the shared library that generated above */ + // The function should also initialize the external veriable + // in the shred library + // Call verilog_module_so.find_func(VERILOG_INIT_FUNC) + // Call verilog_module_so.find_func(VERILOG_RESET_FUNC) + // shared library function reset() should be defalt generated + // There would be a function called general_sim() + // general_sim() could accept input and output of all port with + // the help of port map stored in the verilog_data + try { + // obtain exclusive access for duration of load_lib() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->load_lib(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Initialize sim */ + this->sim = NULL; + } + + /* + * Our virtual destructor. + */ + verilog_axi_ff_impl::~verilog_axi_ff_impl() + { + // There should not be any errors in destructor + typedef void (*Close_func) (void); + Close_func axi_close; + axi_close = + (Close_func)this->verilog_module_so.find_func("AXI_close"); + if (axi_close != NULL) + axi_close(); + + this->release_lib(); + } + + void + verilog_axi_ff_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ + ninput_items_required[0] = (int) round(IO_ratio * noutput_items); + } + + int + verilog_axi_ff_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const ITYPE *in = (const ITYPE *) input_items[0]; + OTYPE *out = (OTYPE *) output_items[0]; + + // Initial and Reset the module + if (NULL == this->sim) + { + typedef void (*Initial_func) (void); + typedef void (*Reset_func) (unsigned int flag); + + Initial_func axi_init; + Reset_func axi_reset; + + axi_init = + (Initial_func)this->verilog_module_so.find_func("AXI_init"); + axi_reset = + (Reset_func)this->verilog_module_so.find_func("AXI_reset"); + + if ((NULL == axi_init) or (NULL == axi_reset)) { + throw std::runtime_error("can't find correct AXI_init or AXI_reset in shared library"); + return _EXIT_FAILURE; + } + + axi_init(); + axi_reset(this->module_flag); + + this->sim = + (Simulation_func)this->verilog_module_so.find_func("AXI_async_transfer_ff"); + + if (NULL == this->sim) { + throw std::runtime_error("can't find correct AXI_async_transfer_ff in shared library"); + return _EXIT_FAILURE; + } + } + + + // Do <+signal processing+> + unsigned int input_i; + unsigned int output_i; + for (input_i = 0, output_i = 0; output_i < noutput_items && input_i < ninput_items[0];) + { + unsigned char status_code; + + try { + status_code = + this->sim(in[input_i], out[output_i], this->main_time); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + // input + if (status_code & (1 << 1)) { + ++input_i; + } + // output + if (status_code & 1) { + if (this->skip_output_items > 0) + --this->skip_output_items; + else + ++output_i; + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (input_i); + + // Tell runtime system how many output items we produced. + return output_i; + } + + + /* gr::verilog::verilog_axi_ff private member functions */ + + int + verilog_axi_ff_impl::generate_so() + { + // const char + const std::string ENTER = "\n"; + const std::string BACKSLASH = "\\"; + + // compile and link error code + int cl_err_code = 0; + + // Shell_cmd class + Shell_cmd bash; + std::string cmd = ""; + + // $ cd ${verilog_module_path} + cmd += "cd "; + cmd += this->verilog_module_path; + cmd += ENTER; + + // $ cp ${makefile_template_path}/axi_module_cl.mk ${verilog_module_path} + // #define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" + cmd += "cp "; + if (!this->overwrite) + cmd += "-n"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->makefile_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->makefile_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + /* alternative solution: + if (this->overwrite) { + cmd += "cp"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + else { + std::string CL_makefile_user_filename = + (this->verilog_module_path + AXI_MODULE_CL_MAKEFILE); + std::string CPP_user_filename = + (this->verilog_module_path + CPP_TEMPLATE_NAME).c_str(); + + bool CL_makefile_flag = this->test_access(CL_makefile_user_filename.c_str(), ""); + bool CPP_flag = this->test_access(CPP_user_filename.c_str(), ""); + + if (!CL_makefile_flag || !CPP_flag) { + cmd += "cp "; + + if (!CL_makefile_flag) + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + + if (!CPP_flag) { + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + } + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + } */ + + + // $ make -j -f axi_module_cl.mk \ + // USER_VL_FILENAME=user_module_name.v \ + // USER_CPP_FILENAME=axi_module.cpp \ + // M_DIR=obj_dir + cmd += std::string("") + "make -j -f " + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + "USER_VL_FILENAME=" + this->verilog_module_name; + cmd += std::string(" ") + "USER_CPP_FILENAME=" + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + " M_DIR=" + M_dir; + // cmd += verilator_options: + cmd += std::string(" ") + "VERILATOR_OPTIONS=" + this->verilator_options; + cmd += ENTER; + + cmd += ENTER; + + try { + cl_err_code = bash.exec(cmd.c_str()); + if (cl_err_code == _EXIT_FAILURE) { + throw std::runtime_error("Shell_cmd execute error"); + } + + // Output the message + // bash.print_msg(std::cout); + } + catch (...) { + bash.print_msg(std::cerr); + throw; + } + + return cl_err_code; + } + + int + verilog_axi_ff_impl::load_lib() + { + int lib_err_code; + lib_err_code = + this->verilog_module_so.load_lib((this->verilog_module_path + M_dir).c_str(), + SHARED_LIB_NAME); + if (lib_err_code == _EXIT_FAILURE) { + throw std::runtime_error("can't load shared library"); + } + + return lib_err_code; + } + + int + verilog_axi_ff_impl::release_lib() + { + this->verilog_module_so.close_lib(); + } + + bool + verilog_axi_ff_impl::test_access(const char *filepath, const char *err_msg = "") + { + + if ( access(filepath, R_OK) == _EXIT_FAILURE ) { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % filepath + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + bool + verilog_axi_ff_impl::check_env(const char *package, const char *err_msg = "") + { + + Shell_cmd bash; + bash.exec((std::string("which ") + package).c_str()); + if (bash.get_msg(0) == "") { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % package + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + /* gr::verilog::verilog_axi_ff private member functions */ + + } /* namespace verilog */ +} /* namespace gr */ + diff --git a/lib/verilog_axi_ff_impl.h b/lib/verilog_axi_ff_impl.h new file mode 100644 index 0000000..33f8fae --- /dev/null +++ b/lib/verilog_axi_ff_impl.h @@ -0,0 +1,138 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_FF_IMPL_H +#define INCLUDED_VERILOG_VERILOG_AXI_FF_IMPL_H + +#include +#include + +#include "verilog/Shared_lib.h" + +#define SLASH "/" + +namespace gr { + namespace verilog { + + class verilog_axi_ff_impl : public verilog_axi_ff + { + private: + /* gr::verilog::verilog_axi_ff private member variables */ + typedef float ITYPE; + typedef float OTYPE; + + // The path and name of user's verilog module + // Construct by (const char *filename) + std::string verilog_module_path; + std::string verilog_module_name; + + // The path of makefile template + std::string makefile_template_path; + + // The path of cpp template + std::string cpp_template_path; + + // The class that control the shared library + // Use verilog_module_so.load_lib(std::string verilog_module_path, std::string lib_name) to load library + // Use verilog_module_so.find_func(std::string func_name) to get the function + // Use verilog_module_so.release_lib(std::string string lib_name) to release the library + Shared_lib verilog_module_so; + + // typedef void (*Simulation_func) + typedef unsigned char (*Simulation_func) (const ITYPE &verilog_input, const OTYPE &verilog_ouput, const unsigned int &main_time); + Simulation_func sim; + + + unsigned int main_time; + + unsigned int skip_output_items; + + // overwrite user templates in the path + bool overwrite; + + // used for forecast + float IO_ratio; + + // thread safe + boost::mutex vl_mutex; + + std::string verilator_options; + + // the parameter send to the template cpp code in function reset(unsiged int) + // user can make use of it + unsigned int module_flag; + + /* gr::verilog::verilog_axi_ff private member variables */ + + + /* gr::verilog::verilog_axi_ff private member functions */ + + /* Construct routine */ + // The function that call Verilator (Makefile) to generate the cpp code + //int generate_verilator_file() throw(std::runtime_error); + + /* + // Parse the Verilator generate file and extract the port map + // The port map should be stored in Veriloag_data verilog_data + int init_port_map() throw(std::logic_error); + */ + + // The function that call g++ (Makefile) to generate the shared library + // There might be some modifications on the tempalte cpp interface file + // ! generate_verilator_file will be included in the this->generate_so() + int generate_so(); + + // The function that load the shared library that generated above + // with the Shared_lib verilog_module_so + int load_lib(); + /* Construct routine */ + + /* Destruct routine */ + + int release_lib(); + + /* Destruct routine */ + + bool test_access(const char *filepath, const char *err_msg); + + bool check_env(const char *package, const char *err_msg); + + /* gr::verilog::verilog_axi_ff private member functions */ + + public: + verilog_axi_ff_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + ~verilog_axi_ff_impl(); + + // Where all the action really happens + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_FF_IMPL_H */ + diff --git a/lib/verilog_axi_ii_impl.cc b/lib/verilog_axi_ii_impl.cc new file mode 100644 index 0000000..ee5fc66 --- /dev/null +++ b/lib/verilog_axi_ii_impl.cc @@ -0,0 +1,444 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "verilog_axi_ii_impl.h" +#include +#include +#include +#include + + +#include "verilog/constants.h" + +#include "verilog/Shell_cmd.h" +#include "verilog/Shared_lib.h" + +#define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" +#define CPP_TEMPLATE_NAME "axi_module.cpp" +#define HEADER_TEMPLATE_NAME "axi_module.h" +#define SHARED_LIB_NAME "lib_axi_module.so" +#define M_dir "obj_dir" + +#define MAKEFILE_TEMPLATE_PATH templatedir() +#define CPP_TEMPLATE_PATH templatedir() + +#define _EXIT_SUCCESS 0 +#define _EXIT_FAILURE -1 + +namespace gr { + namespace verilog { + + verilog_axi_ii::sptr + verilog_axi_ii::make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, unsigned int skip_output_items) + { + return gnuradio::get_initial_sptr + (new verilog_axi_ii_impl(filename, overwrite, IO_ratio, + verilator_options, module_flag, skip_output_items)); + } + + /* + * The private constructor + */ + verilog_axi_ii_impl::verilog_axi_ii_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items) + : gr::block("verilog_axi_ii", + gr::io_signature::make(1, 1, sizeof(ITYPE)), + gr::io_signature::make(1, 1, sizeof(OTYPE))) + { + /* Get module_name and module_path */ + std::string filename_temp(filename); + std::size_t filename_pos = filename_temp.rfind(SLASH); + if (std::string::npos == filename_pos) { + GR_LOG_WARN(d_logger, "filename error"); + } + + this->verilog_module_name = filename_temp.substr(filename_pos + 1); + this->verilog_module_path = filename_temp.substr(0, filename_pos + 1); + + // Test access + this->test_access(filename, + (std::string("\ncan't access verilog file in: ") + + this->verilog_module_path).c_str()); + + /* Initialize makefile_template_path and cpp_template_path */ + this->makefile_template_path = MAKEFILE_TEMPLATE_PATH; + this->cpp_template_path = CPP_TEMPLATE_PATH; + // Test access + this->test_access((this->makefile_template_path + AXI_MODULE_CL_MAKEFILE).c_str(), + (std::string("\ncan't access makefile template in: ") + + this->makefile_template_path).c_str()); + this->test_access((this->cpp_template_path + CPP_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access cpp template in: ") + + this->cpp_template_path).c_str()); + this->test_access((this->cpp_template_path + HEADER_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access header template in: ") + + this->cpp_template_path).c_str()); + + // Reset the initial time + this->main_time = 0; + + // Initial skip_output_items + this->skip_output_items = skip_output_items; + + // Set overwrite + this->overwrite = overwrite; + + // Set IO_ratio + this->IO_ratio = IO_ratio; + + // Set verilator options + this->verilator_options = std::string(verilator_options); + + // Set module_flag + this->module_flag = module_flag; + + /* Call Verilator (Makefile) to generate the cpp code */ + // There will be a Shell_cmd object created in the function to + // run configure.sh + // configure.sh will copy the makefile template and modify it + // for the verilog module + // the Shell_cmd will run make at the verilog module path + + // Check enviroments : make, g++, verilator + this->check_env("make", "can't find make"); + this->check_env("g++", "can't find g++"); + this->check_env("verilator", "can't find verilator"); + + //try { + // this->generate_verilator_file(); + //} catch (...) { + // + //} + + /* Generate shared library and initialize verilog_module_so */ + // There will be a Shell_cmd object created in the function to + // run make at the verilog module path + // ! generate_verilator_file will be included in the this->generate_so() + try { + // obtain exclusive access for duration of generate_so() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->generate_so(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Load the shared library that generated above */ + // The function should also initialize the external veriable + // in the shred library + // Call verilog_module_so.find_func(VERILOG_INIT_FUNC) + // Call verilog_module_so.find_func(VERILOG_RESET_FUNC) + // shared library function reset() should be defalt generated + // There would be a function called general_sim() + // general_sim() could accept input and output of all port with + // the help of port map stored in the verilog_data + try { + // obtain exclusive access for duration of load_lib() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->load_lib(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Initialize sim */ + this->sim = NULL; + } + + /* + * Our virtual destructor. + */ + verilog_axi_ii_impl::~verilog_axi_ii_impl() + { + // There should not be any errors in destructor + typedef void (*Close_func) (void); + Close_func axi_close; + axi_close = + (Close_func)this->verilog_module_so.find_func("AXI_close"); + if (axi_close != NULL) + axi_close(); + + this->release_lib(); + } + + void + verilog_axi_ii_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ + ninput_items_required[0] = (int) round(IO_ratio * noutput_items); + } + + int + verilog_axi_ii_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const ITYPE *in = (const ITYPE *) input_items[0]; + OTYPE *out = (OTYPE *) output_items[0]; + + // Initial and Reset the module + if (NULL == this->sim) + { + typedef void (*Initial_func) (void); + typedef void (*Reset_func) (unsigned int flag); + + Initial_func axi_init; + Reset_func axi_reset; + + axi_init = + (Initial_func)this->verilog_module_so.find_func("AXI_init"); + axi_reset = + (Reset_func)this->verilog_module_so.find_func("AXI_reset"); + + if ((NULL == axi_init) or (NULL == axi_reset)) { + throw std::runtime_error("can't find correct AXI_init or AXI_reset in shared library"); + return _EXIT_FAILURE; + } + + axi_init(); + axi_reset(this->module_flag); + + this->sim = + (Simulation_func)this->verilog_module_so.find_func("AXI_async_transfer_ii"); + + if (NULL == this->sim) { + throw std::runtime_error("can't find correct AXI_async_transfer_ii in shared library"); + return _EXIT_FAILURE; + } + } + + + // Do <+signal processing+> + unsigned int input_i; + unsigned int output_i; + for (input_i = 0, output_i = 0; output_i < noutput_items && input_i < ninput_items[0];) + { + unsigned char status_code; + + try { + status_code = + this->sim(in[input_i], out[output_i], this->main_time); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + // input + if (status_code & (1 << 1)) { + ++input_i; + } + // output + if (status_code & 1) { + if (this->skip_output_items > 0) + --this->skip_output_items; + else + ++output_i; + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (input_i); + + // Tell runtime system how many output items we produced. + return output_i; + } + + + /* gr::verilog::verilog_axi_ii private member functions */ + + int + verilog_axi_ii_impl::generate_so() + { + // const char + const std::string ENTER = "\n"; + const std::string BACKSLASH = "\\"; + + // compile and link error code + int cl_err_code = 0; + + // Shell_cmd class + Shell_cmd bash; + std::string cmd = ""; + + // $ cd ${verilog_module_path} + cmd += "cd "; + cmd += this->verilog_module_path; + cmd += ENTER; + + // $ cp ${makefile_template_path}/axi_module_cl.mk ${verilog_module_path} + // #define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" + cmd += "cp "; + if (!this->overwrite) + cmd += "-n"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->makefile_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->makefile_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + /* alternative solution: + if (this->overwrite) { + cmd += "cp"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + else { + std::string CL_makefile_user_filename = + (this->verilog_module_path + AXI_MODULE_CL_MAKEFILE); + std::string CPP_user_filename = + (this->verilog_module_path + CPP_TEMPLATE_NAME).c_str(); + + bool CL_makefile_flag = this->test_access(CL_makefile_user_filename.c_str(), ""); + bool CPP_flag = this->test_access(CPP_user_filename.c_str(), ""); + + if (!CL_makefile_flag || !CPP_flag) { + cmd += "cp "; + + if (!CL_makefile_flag) + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + + if (!CPP_flag) { + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + } + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + } */ + + + // $ make -j -f axi_module_cl.mk \ + // USER_VL_FILENAME=user_module_name.v \ + // USER_CPP_FILENAME=axi_module.cpp \ + // M_DIR=obj_dir + cmd += std::string("") + "make -j -f " + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + "USER_VL_FILENAME=" + this->verilog_module_name; + cmd += std::string(" ") + "USER_CPP_FILENAME=" + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + " M_DIR=" + M_dir; + // cmd += verilator_options: + cmd += std::string(" ") + "VERILATOR_OPTIONS=" + this->verilator_options; + cmd += ENTER; + + cmd += ENTER; + + try { + cl_err_code = bash.exec(cmd.c_str()); + if (cl_err_code == _EXIT_FAILURE) { + throw std::runtime_error("Shell_cmd execute error"); + } + + // Output the message + // bash.print_msg(std::cout); + } + catch (...) { + bash.print_msg(std::cerr); + throw; + } + + return cl_err_code; + } + + int + verilog_axi_ii_impl::load_lib() + { + int lib_err_code; + lib_err_code = + this->verilog_module_so.load_lib((this->verilog_module_path + M_dir).c_str(), + SHARED_LIB_NAME); + if (lib_err_code == _EXIT_FAILURE) { + throw std::runtime_error("can't load shared library"); + } + + return lib_err_code; + } + + int + verilog_axi_ii_impl::release_lib() + { + this->verilog_module_so.close_lib(); + } + + bool + verilog_axi_ii_impl::test_access(const char *filepath, const char *err_msg = "") + { + + if ( access(filepath, R_OK) == _EXIT_FAILURE ) { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % filepath + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + bool + verilog_axi_ii_impl::check_env(const char *package, const char *err_msg = "") + { + + Shell_cmd bash; + bash.exec((std::string("which ") + package).c_str()); + if (bash.get_msg(0) == "") { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % package + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + /* gr::verilog::verilog_axi_ii private member functions */ + + } /* namespace verilog */ +} /* namespace gr */ + diff --git a/lib/verilog_axi_ii_impl.h b/lib/verilog_axi_ii_impl.h new file mode 100644 index 0000000..13e0c4a --- /dev/null +++ b/lib/verilog_axi_ii_impl.h @@ -0,0 +1,138 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_II_IMPL_H +#define INCLUDED_VERILOG_VERILOG_AXI_II_IMPL_H + +#include +#include + +#include "verilog/Shared_lib.h" + +#define SLASH "/" + +namespace gr { + namespace verilog { + + class verilog_axi_ii_impl : public verilog_axi_ii + { + private: + /* gr::verilog::verilog_axi_ii private member variables */ + typedef unsigned int ITYPE; + typedef unsigned int OTYPE; + + // The path and name of user's verilog module + // Construct by (const char *filename) + std::string verilog_module_path; + std::string verilog_module_name; + + // The path of makefile template + std::string makefile_template_path; + + // The path of cpp template + std::string cpp_template_path; + + // The class that control the shared library + // Use verilog_module_so.load_lib(std::string verilog_module_path, std::string lib_name) to load library + // Use verilog_module_so.find_func(std::string func_name) to get the function + // Use verilog_module_so.release_lib(std::string string lib_name) to release the library + Shared_lib verilog_module_so; + + // typedef void (*Simulation_func) + typedef unsigned char (*Simulation_func) (const ITYPE &verilog_input, const OTYPE &verilog_ouput, const unsigned int &main_time); + Simulation_func sim; + + + unsigned int main_time; + + unsigned int skip_output_items; + + // overwrite user templates in the path + bool overwrite; + + // used for forecast + float IO_ratio; + + // thread safe + boost::mutex vl_mutex; + + std::string verilator_options; + + // the parameter send to the template cpp code in function reset(unsiged int) + // user can make use of it + unsigned int module_flag; + + /* gr::verilog::verilog_axi_ii private member variables */ + + + /* gr::verilog::verilog_axi_ii private member functions */ + + /* Construct routine */ + // The function that call Verilator (Makefile) to generate the cpp code + //int generate_verilator_file() throw(std::runtime_error); + + /* + // Parse the Verilator generate file and extract the port map + // The port map should be stored in Veriloag_data verilog_data + int init_port_map() throw(std::logic_error); + */ + + // The function that call g++ (Makefile) to generate the shared library + // There might be some modifications on the tempalte cpp interface file + // ! generate_verilator_file will be included in the this->generate_so() + int generate_so(); + + // The function that load the shared library that generated above + // with the Shared_lib verilog_module_so + int load_lib(); + /* Construct routine */ + + /* Destruct routine */ + + int release_lib(); + + /* Destruct routine */ + + bool test_access(const char *filepath, const char *err_msg); + + bool check_env(const char *package, const char *err_msg); + + /* gr::verilog::verilog_axi_ii private member functions */ + + public: + verilog_axi_ii_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + ~verilog_axi_ii_impl(); + + // Where all the action really happens + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_II_IMPL_H */ + diff --git a/lib/verilog_axi_ss_impl.cc b/lib/verilog_axi_ss_impl.cc new file mode 100644 index 0000000..9ddbe27 --- /dev/null +++ b/lib/verilog_axi_ss_impl.cc @@ -0,0 +1,444 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "verilog_axi_ss_impl.h" +#include +#include +#include +#include + + +#include "verilog/constants.h" + +#include "verilog/Shell_cmd.h" +#include "verilog/Shared_lib.h" + +#define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" +#define CPP_TEMPLATE_NAME "axi_module.cpp" +#define HEADER_TEMPLATE_NAME "axi_module.h" +#define SHARED_LIB_NAME "lib_axi_module.so" +#define M_dir "obj_dir" + +#define MAKEFILE_TEMPLATE_PATH templatedir() +#define CPP_TEMPLATE_PATH templatedir() + +#define _EXIT_SUCCESS 0 +#define _EXIT_FAILURE -1 + +namespace gr { + namespace verilog { + + verilog_axi_ss::sptr + verilog_axi_ss::make(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, unsigned int skip_output_items) + { + return gnuradio::get_initial_sptr + (new verilog_axi_ss_impl(filename, overwrite, IO_ratio, + verilator_options, module_flag, skip_output_items)); + } + + /* + * The private constructor + */ + verilog_axi_ss_impl::verilog_axi_ss_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items) + : gr::block("verilog_axi_ss", + gr::io_signature::make(1, 1, sizeof(ITYPE)), + gr::io_signature::make(1, 1, sizeof(OTYPE))) + { + /* Get module_name and module_path */ + std::string filename_temp(filename); + std::size_t filename_pos = filename_temp.rfind(SLASH); + if (std::string::npos == filename_pos) { + GR_LOG_WARN(d_logger, "filename error"); + } + + this->verilog_module_name = filename_temp.substr(filename_pos + 1); + this->verilog_module_path = filename_temp.substr(0, filename_pos + 1); + + // Test access + this->test_access(filename, + (std::string("\ncan't access verilog file in: ") + + this->verilog_module_path).c_str()); + + /* Initialize makefile_template_path and cpp_template_path */ + this->makefile_template_path = MAKEFILE_TEMPLATE_PATH; + this->cpp_template_path = CPP_TEMPLATE_PATH; + // Test access + this->test_access((this->makefile_template_path + AXI_MODULE_CL_MAKEFILE).c_str(), + (std::string("\ncan't access makefile template in: ") + + this->makefile_template_path).c_str()); + this->test_access((this->cpp_template_path + CPP_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access cpp template in: ") + + this->cpp_template_path).c_str()); + this->test_access((this->cpp_template_path + HEADER_TEMPLATE_NAME).c_str(), + (std::string("\ncan't access header template in: ") + + this->cpp_template_path).c_str()); + + // Reset the initial time + this->main_time = 0; + + // Initial skip_output_items + this->skip_output_items = skip_output_items; + + // Set overwrite + this->overwrite = overwrite; + + // Set IO_ratio + this->IO_ratio = IO_ratio; + + // Set verilator options + this->verilator_options = std::string(verilator_options); + + // Set module_flag + this->module_flag = module_flag; + + /* Call Verilator (Makefile) to generate the cpp code */ + // There will be a Shell_cmd object created in the function to + // run configure.sh + // configure.sh will copy the makefile template and modify it + // for the verilog module + // the Shell_cmd will run make at the verilog module path + + // Check enviroments : make, g++, verilator + this->check_env("make", "can't find make"); + this->check_env("g++", "can't find g++"); + this->check_env("verilator", "can't find verilator"); + + //try { + // this->generate_verilator_file(); + //} catch (...) { + // + //} + + /* Generate shared library and initialize verilog_module_so */ + // There will be a Shell_cmd object created in the function to + // run make at the verilog module path + // ! generate_verilator_file will be included in the this->generate_so() + try { + // obtain exclusive access for duration of generate_so() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->generate_so(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Load the shared library that generated above */ + // The function should also initialize the external veriable + // in the shred library + // Call verilog_module_so.find_func(VERILOG_INIT_FUNC) + // Call verilog_module_so.find_func(VERILOG_RESET_FUNC) + // shared library function reset() should be defalt generated + // There would be a function called general_sim() + // general_sim() could accept input and output of all port with + // the help of port map stored in the verilog_data + try { + // obtain exclusive access for duration of load_lib() + gr::thread::scoped_lock lock(this->vl_mutex); + + this->load_lib(); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + /* Initialize sim */ + this->sim = NULL; + } + + /* + * Our virtual destructor. + */ + verilog_axi_ss_impl::~verilog_axi_ss_impl() + { + // There should not be any errors in destructor + typedef void (*Close_func) (void); + Close_func axi_close; + axi_close = + (Close_func)this->verilog_module_so.find_func("AXI_close"); + if (axi_close != NULL) + axi_close(); + + this->release_lib(); + } + + void + verilog_axi_ss_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ + ninput_items_required[0] = (int) round(IO_ratio * noutput_items); + } + + int + verilog_axi_ss_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const ITYPE *in = (const ITYPE *) input_items[0]; + OTYPE *out = (OTYPE *) output_items[0]; + + // Initial and Reset the module + if (NULL == this->sim) + { + typedef void (*Initial_func) (void); + typedef void (*Reset_func) (unsigned int flag); + + Initial_func axi_init; + Reset_func axi_reset; + + axi_init = + (Initial_func)this->verilog_module_so.find_func("AXI_init"); + axi_reset = + (Reset_func)this->verilog_module_so.find_func("AXI_reset"); + + if ((NULL == axi_init) or (NULL == axi_reset)) { + throw std::runtime_error("can't find correct AXI_init or AXI_reset in shared library"); + return _EXIT_FAILURE; + } + + axi_init(); + axi_reset(this->module_flag); + + this->sim = + (Simulation_func)this->verilog_module_so.find_func("AXI_async_transfer_ss"); + + if (NULL == this->sim) { + throw std::runtime_error("can't find correct AXI_async_transfer_ss in shared library"); + return _EXIT_FAILURE; + } + } + + + // Do <+signal processing+> + unsigned int input_i; + unsigned int output_i; + for (input_i = 0, output_i = 0; output_i < noutput_items && input_i < ninput_items[0];) + { + unsigned char status_code; + + try { + status_code = + this->sim(in[input_i], out[output_i], this->main_time); + } catch (std::runtime_error) { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % this->verilog_module_path.c_str() + % strerror(errno)); + throw; + } + + // input + if (status_code & (1 << 1)) { + ++input_i; + } + // output + if (status_code & 1) { + if (this->skip_output_items > 0) + --this->skip_output_items; + else + ++output_i; + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (input_i); + + // Tell runtime system how many output items we produced. + return output_i; + } + + + /* gr::verilog::verilog_axi_ss private member functions */ + + int + verilog_axi_ss_impl::generate_so() + { + // const char + const std::string ENTER = "\n"; + const std::string BACKSLASH = "\\"; + + // compile and link error code + int cl_err_code = 0; + + // Shell_cmd class + Shell_cmd bash; + std::string cmd = ""; + + // $ cd ${verilog_module_path} + cmd += "cd "; + cmd += this->verilog_module_path; + cmd += ENTER; + + // $ cp ${makefile_template_path}/axi_module_cl.mk ${verilog_module_path} + // #define AXI_MODULE_CL_MAKEFILE "axi_module_cl.mk" + cmd += "cp "; + if (!this->overwrite) + cmd += "-n"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->makefile_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->makefile_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + /* alternative solution: + if (this->overwrite) { + cmd += "cp"; + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + else { + std::string CL_makefile_user_filename = + (this->verilog_module_path + AXI_MODULE_CL_MAKEFILE); + std::string CPP_user_filename = + (this->verilog_module_path + CPP_TEMPLATE_NAME).c_str(); + + bool CL_makefile_flag = this->test_access(CL_makefile_user_filename.c_str(), ""); + bool CPP_flag = this->test_access(CPP_user_filename.c_str(), ""); + + if (!CL_makefile_flag || !CPP_flag) { + cmd += "cp "; + + if (!CL_makefile_flag) + cmd += std::string(" ") + this->makefile_template_path + AXI_MODULE_CL_MAKEFILE; + + if (!CPP_flag) { + cmd += std::string(" ") + this->cpp_template_path + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + this->cpp_template_path + HEADER_TEMPLATE_NAME; + } + cmd += std::string(" ") + this->verilog_module_path; + cmd += ENTER; + } + } */ + + + // $ make -j -f axi_module_cl.mk \ + // USER_VL_FILENAME=user_module_name.v \ + // USER_CPP_FILENAME=axi_module.cpp \ + // M_DIR=obj_dir + cmd += std::string("") + "make -j -f " + AXI_MODULE_CL_MAKEFILE; + cmd += std::string(" ") + "USER_VL_FILENAME=" + this->verilog_module_name; + cmd += std::string(" ") + "USER_CPP_FILENAME=" + CPP_TEMPLATE_NAME; + cmd += std::string(" ") + " M_DIR=" + M_dir; + // cmd += verilator_options: + cmd += std::string(" ") + "VERILATOR_OPTIONS=" + this->verilator_options; + cmd += ENTER; + + cmd += ENTER; + + try { + cl_err_code = bash.exec(cmd.c_str()); + if (cl_err_code == _EXIT_FAILURE) { + throw std::runtime_error("Shell_cmd execute error"); + } + + // Output the message + // bash.print_msg(std::cout); + } + catch (...) { + bash.print_msg(std::cerr); + throw; + } + + return cl_err_code; + } + + int + verilog_axi_ss_impl::load_lib() + { + int lib_err_code; + lib_err_code = + this->verilog_module_so.load_lib((this->verilog_module_path + M_dir).c_str(), + SHARED_LIB_NAME); + if (lib_err_code == _EXIT_FAILURE) { + throw std::runtime_error("can't load shared library"); + } + + return lib_err_code; + } + + int + verilog_axi_ss_impl::release_lib() + { + this->verilog_module_so.close_lib(); + } + + bool + verilog_axi_ss_impl::test_access(const char *filepath, const char *err_msg = "") + { + + if ( access(filepath, R_OK) == _EXIT_FAILURE ) { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % filepath + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + bool + verilog_axi_ss_impl::check_env(const char *package, const char *err_msg = "") + { + + Shell_cmd bash; + bash.exec((std::string("which ") + package).c_str()); + if (bash.get_msg(0) == "") { + if (err_msg != "") { + GR_LOG_ERROR(d_logger, + boost::format("%s: %s") + % package + % strerror(errno)); + throw std::runtime_error(err_msg); + } + + return false; + } + + return true; + } + + /* gr::verilog::verilog_axi_ss private member functions */ + + } /* namespace verilog */ +} /* namespace gr */ + diff --git a/lib/verilog_axi_ss_impl.h b/lib/verilog_axi_ss_impl.h new file mode 100644 index 0000000..69d7aac --- /dev/null +++ b/lib/verilog_axi_ss_impl.h @@ -0,0 +1,138 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 <+YOU OR YOUR COMPANY+>. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VERILOG_VERILOG_AXI_SS_IMPL_H +#define INCLUDED_VERILOG_VERILOG_AXI_SS_IMPL_H + +#include +#include + +#include "verilog/Shared_lib.h" + +#define SLASH "/" + +namespace gr { + namespace verilog { + + class verilog_axi_ss_impl : public verilog_axi_ss + { + private: + /* gr::verilog::verilog_axi_ss private member variables */ + typedef unsigned short ITYPE; + typedef unsigned short OTYPE; + + // The path and name of user's verilog module + // Construct by (const char *filename) + std::string verilog_module_path; + std::string verilog_module_name; + + // The path of makefile template + std::string makefile_template_path; + + // The path of cpp template + std::string cpp_template_path; + + // The class that control the shared library + // Use verilog_module_so.load_lib(std::string verilog_module_path, std::string lib_name) to load library + // Use verilog_module_so.find_func(std::string func_name) to get the function + // Use verilog_module_so.release_lib(std::string string lib_name) to release the library + Shared_lib verilog_module_so; + + // typedef void (*Simulation_func) + typedef unsigned char (*Simulation_func) (const ITYPE &verilog_input, const OTYPE &verilog_ouput, const unsigned int &main_time); + Simulation_func sim; + + + unsigned int main_time; + + unsigned int skip_output_items; + + // overwrite user templates in the path + bool overwrite; + + // used for forecast + float IO_ratio; + + // thread safe + boost::mutex vl_mutex; + + std::string verilator_options; + + // the parameter send to the template cpp code in function reset(unsiged int) + // user can make use of it + unsigned int module_flag; + + /* gr::verilog::verilog_axi_ss private member variables */ + + + /* gr::verilog::verilog_axi_ss private member functions */ + + /* Construct routine */ + // The function that call Verilator (Makefile) to generate the cpp code + //int generate_verilator_file() throw(std::runtime_error); + + /* + // Parse the Verilator generate file and extract the port map + // The port map should be stored in Veriloag_data verilog_data + int init_port_map() throw(std::logic_error); + */ + + // The function that call g++ (Makefile) to generate the shared library + // There might be some modifications on the tempalte cpp interface file + // ! generate_verilator_file will be included in the this->generate_so() + int generate_so(); + + // The function that load the shared library that generated above + // with the Shared_lib verilog_module_so + int load_lib(); + /* Construct routine */ + + /* Destruct routine */ + + int release_lib(); + + /* Destruct routine */ + + bool test_access(const char *filepath, const char *err_msg); + + bool check_env(const char *package, const char *err_msg); + + /* gr::verilog::verilog_axi_ss private member functions */ + + public: + verilog_axi_ss_impl(const char *filename, bool overwrite, float IO_ratio, + const char *verilator_options, unsigned int module_flag, + unsigned int skip_output_items); + ~verilog_axi_ss_impl(); + + // Where all the action really happens + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace verilog +} // namespace gr + +#endif /* INCLUDED_VERILOG_VERILOG_AXI_SS_IMPL_H */ + diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 536077c..ef31839 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -41,3 +41,7 @@ include(GrTest) set(GR_TEST_TARGET_DEPS gnuradio-verilog) set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) +GR_ADD_TEST(qa_verilog_axi_ii ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_verilog_axi_ii.py) +GR_ADD_TEST(qa_verilog_axi_ff ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_verilog_axi_ff.py) +GR_ADD_TEST(qa_verilog_axi_ss ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_verilog_axi_ss.py) +GR_ADD_TEST(qa_verilog_axi_cc ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_verilog_axi_cc.py) diff --git a/python/qa_verilog_axi_cc.py b/python/qa_verilog_axi_cc.py new file mode 100755 index 0000000..9c27f38 --- /dev/null +++ b/python/qa_verilog_axi_cc.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 <+YOU OR YOUR COMPANY+>. +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +from gnuradio import blocks +import verilog_swig as verilog + +class qa_verilog_axi_cc (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_t (self): + # set up fg + self.tb.run () + # check data + + +if __name__ == '__main__': + gr_unittest.run(qa_verilog_axi_cc, "qa_verilog_axi_cc.xml") diff --git a/python/qa_verilog_axi_ff.py b/python/qa_verilog_axi_ff.py new file mode 100755 index 0000000..c7c24c8 --- /dev/null +++ b/python/qa_verilog_axi_ff.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 <+YOU OR YOUR COMPANY+>. +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +from gnuradio import blocks +import verilog_swig as verilog + +class qa_verilog_axi_ff (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_t (self): + # set up fg + src_data = (1.2, 3.8, 5.7, 9.4, 10.2, 12.4, 17.5, 19.2, 21.4, 12.3, 45.5, 29.3) + expected_result = (1.2, 3.8, 5.7, 9.4, 10.2, 12.4, 17.5, 19.2, 21.4, 12.3, 45.5, 29.3) + src = blocks.vector_source_f(src_data) + vl = verilog.verilog_axi_ff("/home/bowen/Downloads/temp/saxi_passthru.v", True, 1.0, "-Wall", 0, 0) + dst = blocks.vector_sink_f() + + self.tb.connect(src, vl) + self.tb.connect(vl, dst) + self.tb.run() + # check data + + + result_data = dst.data() + print (expected_result) + print (result_data) + def round_f(x): + return round(x, 3) + round_result_data = tuple(map(round_f, result_data)) + print (round_result_data) + self.assertFloatTuplesAlmostEqual(expected_result, round_result_data, 12) + + def test_002_t (self): + # set up fg + src_data = (1.2, 3.8, 5.7, 9.4, 10.2, 12.4, 17.5, 19.2, 21.4) + expected_result = (2.4, 7.6, 11.4, 18.8, 20.4, 24.8, 35.0, 38.4, 42.8) + src = blocks.vector_source_f(src_data) + vl = verilog.verilog_axi_ff("/home/bowen/Downloads/double/double_axi.v", True, 1.0, "", 0, 0) + dst = blocks.vector_sink_f() + + self.tb.connect(src, vl) + self.tb.connect(vl, dst) + self.tb.run() + # check data + result_data = dst.data() + print (expected_result) + print (result_data) + def round_f(x): + return round(x, 3) + round_result_data = tuple(map(round_f, result_data)) + print (round_result_data) + self.assertFloatTuplesAlmostEqual(expected_result, round_result_data, 9) + +if __name__ == '__main__': + gr_unittest.run(qa_verilog_axi_ff, "qa_verilog_axi_ff.xml") diff --git a/python/qa_verilog_axi_ii.py b/python/qa_verilog_axi_ii.py new file mode 100755 index 0000000..f482563 --- /dev/null +++ b/python/qa_verilog_axi_ii.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 <+YOU OR YOUR COMPANY+>. +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +from gnuradio import blocks +import verilog_swig as verilog + +class qa_verilog_axi_ii (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_t (self): + # set up fg + src_data = (1, 3, 5, 9, 10, 12, 17, 19, 21, 12, 45, 29) + expected_result = (1, 3, 5, 9, 10, 12, 17, 19, 21, 12, 45, 29) + src = blocks.vector_source_i(src_data) + vl = verilog.verilog_axi_ii("/home/bowen/Downloads/temp/saxi_passthru.v", True, 1.0, "-Wall", 0, 0) + dst = blocks.vector_sink_i() + + self.tb.connect(src, vl) + self.tb.connect(vl, dst) + self.tb.run() + # check data + result_data = dst.data() + print (expected_result) + print (result_data) + self.assertFloatTuplesAlmostEqual(expected_result, result_data, 12) + + def test_002_t (self): + # set up fg + src_data = (1, 3, 5, 9, 10, 12, 17, 19, 21) + expected_result = (2, 6, 10, 18, 20, 24, 34, 38, 42) + src = blocks.vector_source_i(src_data) + vl = verilog.verilog_axi_ii("/home/bowen/Downloads/double/double_axi.v", True, 1.0, "", 0, 0) + dst = blocks.vector_sink_i() + + self.tb.connect(src, vl) + self.tb.connect(vl, dst) + self.tb.run() + # check data + result_data = dst.data() + print (expected_result) + print (result_data) + self.assertFloatTuplesAlmostEqual(expected_result, result_data, 9) + + +if __name__ == '__main__': + gr_unittest.run(qa_verilog_axi_ii, "qa_verilog_axi_ii.xml") diff --git a/python/qa_verilog_axi_ss.py b/python/qa_verilog_axi_ss.py new file mode 100755 index 0000000..e6132f8 --- /dev/null +++ b/python/qa_verilog_axi_ss.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 <+YOU OR YOUR COMPANY+>. +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +from gnuradio import blocks +import verilog_swig as verilog + +class qa_verilog_axi_ss (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_t (self): + # set up fg + src_data = (1, 3, 5, 9, 10, 12, 17, 19, 21, 12, 45, 29) + expected_result = (1, 3, 5, 9, 10, 12, 17, 19, 21, 12, 45, 29) + src = blocks.vector_source_s(src_data) + vl = verilog.verilog_axi_ss("/home/bowen/Downloads/temp/saxi_passthru.v", True, 1.0, "-Wall", 0, 0) + dst = blocks.vector_sink_s() + + self.tb.connect(src, vl) + self.tb.connect(vl, dst) + self.tb.run() + # check data + result_data = dst.data() + print (expected_result) + print (result_data) + self.assertFloatTuplesAlmostEqual(expected_result, result_data, 12) + + def test_002_t (self): + # set up fg + src_data = (1, 3, 5, 9, 10, 12, 17, 19, 21) + expected_result = (2, 6, 10, 18, 20, 24, 34, 38, 42) + src = blocks.vector_source_s(src_data) + vl = verilog.verilog_axi_ss("/home/bowen/Downloads/double/double_axi.v", True, 1.0, "", 0, 0) + dst = blocks.vector_sink_s() + + self.tb.connect(src, vl) + self.tb.connect(vl, dst) + self.tb.run() + # check data + result_data = dst.data() + print (expected_result) + print (result_data) + self.assertFloatTuplesAlmostEqual(expected_result, result_data, 9) + + +if __name__ == '__main__': + gr_unittest.run(qa_verilog_axi_ss, "qa_verilog_axi_ss.xml") diff --git a/swig/verilog_swig.i b/swig/verilog_swig.i index 5de096f..ec01e18 100644 --- a/swig/verilog_swig.i +++ b/swig/verilog_swig.i @@ -8,6 +8,18 @@ %include "verilog_swig_doc.i" %{ +#include "verilog/verilog_axi_ii.h" +#include "verilog/verilog_axi_ff.h" +#include "verilog/verilog_axi_ss.h" +#include "verilog/verilog_axi_cc.h" %} +%include "verilog/verilog_axi_ii.h" +GR_SWIG_BLOCK_MAGIC2(verilog, verilog_axi_ii); +%include "verilog/verilog_axi_ff.h" +GR_SWIG_BLOCK_MAGIC2(verilog, verilog_axi_ff); +%include "verilog/verilog_axi_ss.h" +GR_SWIG_BLOCK_MAGIC2(verilog, verilog_axi_ss); +%include "verilog/verilog_axi_cc.h" +GR_SWIG_BLOCK_MAGIC2(verilog, verilog_axi_cc); diff --git a/templates/CMakeLists.txt b/templates/CMakeLists.txt new file mode 100644 index 0000000..d99fac3 --- /dev/null +++ b/templates/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2011,2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +######################################################################## +# Install gr-verilog template +######################################################################## +install(FILES + axi_module_cl.mk + axi_module.h + axi_module.cpp DESTINATION ${GR_PKG_DATA_DIR}/templates +) diff --git a/templates/axi_module.cpp b/templates/axi_module.cpp new file mode 100644 index 0000000..141ccb7 --- /dev/null +++ b/templates/axi_module.cpp @@ -0,0 +1,465 @@ +/* -*- c++ -*- */ +/* + * DESCRIPTION: The template of the AXI interface + * This file is the implement of the shared library used in gr-verilog verilog_axi_ii + * This file should not be modified + */ +#include "axi_module.h" +#include +#include +#include + +// define the _USER_MODIFIED_ to avoid unnecessary code being compiled +/* #define _USER_MODIFIED_ */ + +#define MAX_ITERATION 512 +#define SKIP_OUTPUT_ITEMS 0 + +#define ACLK ACLK +#define ARESETn ARESETn +#define TVALID_IN TVALID_IN +#define TREADY_IN TREADY_IN +#define TVALID_OUT TVALID_OUT +#define TREADY_OUT TREADY_OUT +#define TDATA_IN TDATA_IN +#define TDATA_OUT TDATA_OUT +/* + * AXI signals: + * ACLK input + * ARESETn input + * TVALID_IN input + * TREADY_IN output + * TVALID_OUT output + * TREADY_OUT input + * TDATA_IN[31:0] input + * TDATA_OUT[31:0] output + */ + +unsigned int skip_output_items = 0; + + +void AXI_init() +{ + int argc = 0; + char** argv = NULL; + Verilated::commandArgs(argc, argv); + + skip_output_items = SKIP_OUTPUT_ITEMS; + + if (NULL == top) + top = new Vaxi_module; +} + +void AXI_reset(unsigned int module_flag) +{ + top->ACLK = 0; + top->ARESETn = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + top->ARESETn = 1; + top->ACLK = 0; + top->eval(); +} + +/* Deprecated +void AXI_sync_transfer_ii(const unsigned int &gr_input, + unsigned int &gr_output, + unsigned int &time) +{ + // Suppose the module is SYNC + // input:ouput => 1:1 + unsigned int cycle_tmp = 0; + bool in_tranfer_flag = false; + bool out_transfer_flag = false; + bool transfer_flag = false; + + top->TVALID_IN = (uint8_t)true; + top->TREADY_OUT = (uint8_t)true; + + while (!transfer_flag) { + + if ((uint8_t)true == top->TREADY_IN) { + top->TDATA_IN = (unsigned int)gr_input; + in_tranfer_flag = true; + } + + if ((uint8_t)true == top->TVALID_OUT) { + gr_output = (unsigned int)top->TDATA_OUT; + out_transfer_flag = true; + } + + top->ACLK = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + + ++cycle_tmp; + + transfer_flag = in_tranfer_flag && out_transfer_flag; + } + + time += cycle_tmp; +} +*/ + +#ifndef _USER_MODIFIED_ +/* verilog_axi_ii */ +unsigned char AXI_async_transfer_ii(const unsigned int &gr_input, + unsigned int &gr_output, + unsigned int &time) +{ + // Suppose the module is not SYNC + // input:ouput != 1:1 + unsigned char status_code = 0; + /* status_code status + * 00 ERROR + * 01 N/O (only ouput) + * 10 I/N (only input) + * 11 I/O (both input and output) + */ + + unsigned int cycle_tmp = 0; + bool in_tranfer_flag = false; + bool out_transfer_flag = false; + bool transfer_flag = false; + + top->TVALID_IN = (uint8_t)true; + top->TREADY_OUT = (uint8_t)true; + + while (!transfer_flag && cycle_tmp < MAX_ITERATION) { + + if ((uint8_t)true == top->TREADY_IN) { + top->TDATA_IN = (unsigned int)gr_input; + in_tranfer_flag = true; + } + + top->ACLK = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + + if ((uint8_t)true == top->TVALID_OUT) { + if (skip_output_items > 0) { + --skip_output_items; + } + else { + gr_output = (unsigned int)top->TDATA_OUT; + out_transfer_flag = true; + } + } + + ++cycle_tmp; + + transfer_flag = in_tranfer_flag || out_transfer_flag; + } + + status_code = + ((unsigned char)in_tranfer_flag << 1) + + (unsigned char)out_transfer_flag; + + time += cycle_tmp; + + return status_code; +} + +unsigned char AXI_transfer_out_i(unsigned int &gr_output, + unsigned int &time) +{ + // Suppose the module is not SYNC + // input:ouput != 1:1 + unsigned char status_code = 0; + /* status_code status + * 00 ERROR + * 01 N/O (only ouput) + * 10 I/N (only input) + * 11 I/O (both input and output) + */ + + unsigned int cycle_tmp = 0; + bool in_tranfer_flag = false; + bool out_transfer_flag = false; + bool transfer_flag = false; + + top->TVALID_IN = (uint8_t)false; + top->TREADY_OUT = (uint8_t)true; + + while (!transfer_flag && cycle_tmp < MAX_ITERATION) { + + if ((uint8_t)true == top->TREADY_IN) { + in_tranfer_flag = true; + break; + } + + if ((uint8_t)true == top->TVALID_OUT) { + gr_output = (unsigned int)top->TDATA_OUT; + out_transfer_flag = true; + } + + top->ACLK = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + + ++cycle_tmp; + + transfer_flag = in_tranfer_flag || out_transfer_flag; + } + + status_code = + ((unsigned char)in_tranfer_flag << 1) + + (unsigned char)out_transfer_flag; + + time += cycle_tmp; + + return status_code; +} +/* verilog_axi_ii */ + +/* verilog_axi_ss */ +unsigned char AXI_async_transfer_ss(const unsigned short &gr_input, + unsigned short &gr_output, + unsigned int &time) +{ + // Suppose the module is not SYNC + // input:ouput != 1:1 + unsigned char status_code = 0; + /* status_code status + * 00 ERROR + * 01 N/O (only ouput) + * 10 I/N (only input) + * 11 I/O (both input and output) + */ + + unsigned int cycle_tmp = 0; + bool in_tranfer_flag = false; + bool out_transfer_flag = false; + bool transfer_flag = false; + + top->TVALID_IN = (uint8_t)true; + top->TREADY_OUT = (uint8_t)true; + + while (!transfer_flag && cycle_tmp < MAX_ITERATION) { + + if ((uint8_t)true == top->TREADY_IN) { + top->TDATA_IN = (unsigned short)gr_input; + in_tranfer_flag = true; + } + + top->ACLK = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + + if ((uint8_t)true == top->TVALID_OUT) { + if (skip_output_items > 0) { + --skip_output_items; + } + else { + gr_output = (unsigned short)top->TDATA_OUT; + out_transfer_flag = true; + } + } + + ++cycle_tmp; + + transfer_flag = in_tranfer_flag || out_transfer_flag; + } + + status_code = + ((unsigned char)in_tranfer_flag << 1) + + (unsigned char)out_transfer_flag; + + time += cycle_tmp; + + return status_code; +} +/* verilog_axi_ss */ + +/* verilog_axi_ff */ +unsigned int float_to_fix(const float &float_data, + const unsigned int &integer_bits, + const unsigned int &decimal_bits) +{ + /* overflow detection: + // integer_bits + decimal_bits should <= 32 + if (integer_bits + decimal_bits > 32) { + // throw(std::runtime_error); + return -1; + } + if (float_data >= (1 << integer_bits)) { + // throw(std::runtime_error); + return -1; + } + */ + return round(float_data * (1 << decimal_bits)); +} +float fix_to_float(const unsigned int &fix_data, + const unsigned int &integer_bits, + const unsigned int &decimal_bits) +{ + return (float)((int)fix_data) / (1 << decimal_bits); +} +unsigned char AXI_async_transfer_ff(const float &gr_input, + float &gr_output, + unsigned int &time) +{ + // Suppose the module is not SYNC + // input:ouput != 1:1 + unsigned char status_code = 0; + /* status_code status + * 00 ERROR + * 01 N/O (only ouput) + * 10 I/N (only input) + * 11 I/O (both input and output) + */ + + unsigned int cycle_tmp = 0; + bool in_tranfer_flag = false; + bool out_transfer_flag = false; + bool transfer_flag = false; + + top->TVALID_IN = (uint8_t)true; + top->TREADY_OUT = (uint8_t)true; + + while (!transfer_flag && cycle_tmp < MAX_ITERATION) { + + if ((uint8_t)true == top->TREADY_IN) { + // data conversion function + // convert float-point number to fix-point number + // unsigned int float_to_fix(float_data, integer_bits, decimal_bits) + // 16-bit integer and 16-bit decimal by default + top->TDATA_IN = float_to_fix(gr_input, 16, 16); + in_tranfer_flag = true; + } + + top->ACLK = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + + if ((uint8_t)true == top->TVALID_OUT) { + if (skip_output_items > 0) { + --skip_output_items; + } + else { + // data conversion function + // convert fix-point number to float-point number + // float fix_to_float(fix_data, integer_bits, decimal_bits) + // 16-bit integer and 16-bit decimal by default + gr_output = fix_to_float(top->TDATA_OUT , 16, 16); + out_transfer_flag = true; + } + } + + ++cycle_tmp; + + transfer_flag = in_tranfer_flag || out_transfer_flag; + } + + status_code = + ((unsigned char)in_tranfer_flag << 1) + + (unsigned char)out_transfer_flag; + + time += cycle_tmp; + + return status_code; +} +/* verilog_axi_ff */ + + +/* verilog_axi_cc */ +unsigned int complex_to_fix(/*...*/) +{ + /* Please implement this function before use */ + static bool flag = true; + if (flag) { + flag = false; + std::cout << "Please implement this function before use" << std::endl; + } + return 0; +} +std::complex fix_to_complex(/*...*/) +{ + /* Please implement this function before use */ + return 0; +} +unsigned char AXI_async_transfer_cc(const std::complex &gr_input, + std::complex &gr_output, + unsigned int &time) +{ + // Suppose the module is not SYNC + // input:ouput != 1:1 + unsigned char status_code = 0; + /* status_code status + * 00 ERROR + * 01 N/O (only ouput) + * 10 I/N (only input) + * 11 I/O (both input and output) + */ + + unsigned int cycle_tmp = 0; + bool in_tranfer_flag = false; + bool out_transfer_flag = false; + bool transfer_flag = false; + + top->TVALID_IN = (uint8_t)true; + top->TREADY_OUT = (uint8_t)true; + + while (!transfer_flag && cycle_tmp < MAX_ITERATION) { + + if ((uint8_t)true == top->TREADY_IN) { + /* Please implement this function before use */ + top->TDATA_IN = complex_to_fix(/*...*/); + in_tranfer_flag = true; + } + + top->ACLK = 0; + top->eval(); + top->ACLK = 1; + top->eval(); + + if ((uint8_t)true == top->TVALID_OUT) { + if (skip_output_items > 0) { + --skip_output_items; + } + else { + /* Please implement this function before use */ + gr_output = fix_to_complex(/*...*/); + out_transfer_flag = true; + } + } + + ++cycle_tmp; + + transfer_flag = in_tranfer_flag || out_transfer_flag; + } + + status_code = + ((unsigned char)in_tranfer_flag << 1) + + (unsigned char)out_transfer_flag; + + time += cycle_tmp; + + return status_code; +} +/* verilog_axi_cc */ +#endif + + +void AXI_nop() +{ + top->ACLK = 0; + top->eval(); + top->ACLK = 1; +} + +void AXI_close() +{ + top->final(); + if (top != NULL) + { + delete top; + top = NULL; + } +} \ No newline at end of file diff --git a/templates/axi_module.h b/templates/axi_module.h new file mode 100644 index 0000000..c9b2968 --- /dev/null +++ b/templates/axi_module.h @@ -0,0 +1,57 @@ +#pragma once + +#include "Vaxi_module.h" +#include "verilated.h" + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +static Vaxi_module* top = NULL; + +void AXI_init(); + +void AXI_reset(unsigned int module_flag); + +// Deprecated +void AXI_sync_transfer_ii(const unsigned int &gr_input, + unsigned int &gr_output, + unsigned int &time); + +/* verilog_axi_ii */ +unsigned char AXI_async_transfer_ii(const unsigned int &gr_input, + unsigned int &gr_output, + unsigned int &time); + +unsigned char AXI_transfer_out_i(unsigned int &gr_output, + unsigned int &time); +/* verilog_axi_ii */ + +/* verilog_axi_ss */ +unsigned char AXI_async_transfer_ss(const unsigned short &gr_input, + unsigned short &gr_output, + unsigned int &time); +/* verilog_axi_ss */ + +/* verilog_axi_ff */ +unsigned char AXI_async_transfer_ff(const float &gr_input, + float &gr_output, + unsigned int &time); +/* verilog_axi_ff */ + +/* verilog_axi_cc */ +unsigned char AXI_async_transfer_cc(const std::complex &gr_input, + std::complex &gr_output, + unsigned int &time); +/* verilog_axi_cc */ + +void AXI_nop(); + +void AXI_close(); + +#ifdef __cplusplus +} +#endif diff --git a/templates/axi_module_cl.mk b/templates/axi_module_cl.mk new file mode 100644 index 0000000..ac5c153 --- /dev/null +++ b/templates/axi_module_cl.mk @@ -0,0 +1,78 @@ +# gr-verilog -*- Makefile -*- +# DESCRIPTION: Makefile for compiling the source and building the shared library +# axi_module_cl.mk (compile and link) +# make -j -f axi_module_cl.mk USER_VL_FILENAME=user_module_name.v USER_CPP_FILENAME=axi_module.cpp M_DIR=obj_dir + +# Check for sanity to avoid later confusion +ifneq ($(words $(CURDIR)),1) + $(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)') +endif + +###################################################################### +# Set up variables + +# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a +# package inatall, and verilator is in your path. Otherwise find the +# binary relative to $VERILATOR_ROOT (such as when inside the git sources). +ifeq ($(VERILATOR_ROOT),) +VERILATOR = verilator +VERILATOR_COVERAGE = verilator_coverage +else +export VERILATOR_ROOT +VERILATOR = $(VERILATOR_ROOT)/bin/verilator +VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage +endif + +# Call from block +USER_VL_FILENAME = +USER_CPP_FILENAME = +M_DIR = +VERILATOR_OPTIONS = + +VM_PREFIX = Vaxi_module + +VERILATOR_FLAGS = +# Options from block +VERILATOR_FLAGS += $(VERILATOR_OPTIONS) +# Generate -fPIC code for shared library +VERILATOR_FLAGS += -CFLAGS -fPIC +# Change the module to fixed name +VERILATOR_FLAGS += --prefix $(VM_PREFIX) +# Generate C++ in executable form +VERILATOR_FLAGS += -cc --exe +VERILATOR_FLAGS += -o lib_axi_module.so +# Warn abount lint issues; may not want this on less solid designs +# VERILATOR_FLAGS += -Wall + + +###################################################################### +default: run + +run: + @echo + @echo "-- Verilator " + + @echo + @echo "-- VERILATE ----------------" + $(VERILATOR) $(VERILATOR_FLAGS) $(USER_VL_FILENAME) $(USER_CPP_FILENAME) + + @echo + @echo "-- COMPILE & LINK-----------" +# To compile, we can either just do what Verilator asks, +# or call a submakefile where we can override the rules ourselves + $(MAKE) -j -C $(M_DIR) -f $(VM_PREFIX).mk USER_LDFLAGS=-shared + + @echo + @echo "-- DONE --------------------" + @echo + + +###################################################################### +# Other targets + +show-config: + $(VERILATOR) -V + +maintainer-copy:: +clean mostlyclean distclean maintainer-clean:: + -rm -rf obj_dir *.so \ No newline at end of file