Using a Verilog Module in a LegUp Project

By Andrew Canis,

  Filed under: Tutorials
  Comments: None

In this post we will give an example of integrating an existing hardware core into a LegUp software project. This can be useful if you already have Verilog for an IP block which you want to call from your C software code. The example we will use is the Canny edge detector, and we will replace the Sobel filter module with a core written in Verilog.

First you will need to have LegUp installed, you can download LegUp here.

Instructions

First open LegUp and click File, New, LegUp C/C++ Project.

Then select the project template: “Example Project: Canny Edge Detection (Function Pipelining with Arbitrary Bitwidth). Click continue and select your desired FPGA device.

The hardware module we are going to replace is “sobel_filter” which is defined by the following C function in the source file sobel_filter.c:


void sobel_filter(FIFO *input_fifo, FIFO *output_fifo)

Download the sobel filter Verilog source file here. Right click on the project folder in the Project Explorer panel and choose Import, General, File System. Then enter the directory and select the sobel_filter.v file.

If you open the Verilog file sobel_filter.v you will see that there is a top-level module that has the interface expected by LegUp and instantiates the original RTL module. See below:


// wrapper from LegUp interface to original RTL
module sobel_filter
(
clk,
reset,
start,
finish,
canny_entry_call_ready_to_source,
canny_entry_call_valid_from_source,
canny_entry_call_data_from_source,
canny_entry_call1_ready_from_sink,
canny_entry_call1_valid_to_sink,
canny_entry_call1_data_to_sink
);

input clk;
input reset;
input start;
output finish;
output canny_entry_call_ready_to_source;
input canny_entry_call_valid_from_source;
input [7:0] canny_entry_call_data_from_source;
input canny_entry_call1_ready_from_sink;
output canny_entry_call1_valid_to_sink;
output [9:0] canny_entry_call1_data_to_sink;

sobel_filter_rtl inst(
.clk(clk),
.reset(reset),

.data_in(canny_entry_call_data_from_source),
.data_in_valid(canny_entry_call_valid_from_source),
.data_in_ready(canny_entry_call_ready_to_source),

.data_out(canny_entry_call1_data_to_sink),
.data_out_valid(canny_entry_call1_valid_to_sink),
.data_out_ready(canny_entry_call1_ready_from_sink),

.done(finish)
);
defparam inst.IMAGE_SIZE = 512;

endmodule

The module interface argument names need to be taken from the original LegUp output file by looking at the instantiation of the sobel_filter module.

Now open up the config.tcl file in the Project Explorer and enter these two constraints (see documentation):


set_custom_verilog_function "sobel_filter" noMemory
set_custom_verilog_file "../sobel_filter.v"

The first command specifies that we will replace the C function sobel_filter() with a verilog module, the noMemory argument indicates that this module does not share memory with other hardware modules. The second command specifies the path to the verilog file that defines the hardware module.

Note: Make sure you don’t change any constraints from the GUI or this will overwrite these manual changes. In the next version of LegUp we will allow custom Verilog modules to be added from the constraints menu.

Now run LegUp synthesis. If you open the output Verilog file you will notice that it is now missing the sobel_filter module and includes the verilog file specified in the config.tcl:
`include "../sobel_filter.v"
Simulation and co-simulation will still work but now we are using the custom Verilog module that you specified in the config.tcl constraints file.

Be the first to write a comment.

Your feedback