Skip to content

Commit 12d7f02

Browse files
Canny RISCV Demo (#60)
Added Canny_RISCV example, which shows how to use the Canny module in the SoC flow targeting the IcicleKit board. Added a readme for the example.
1 parent d014c95 commit 12d7f02

16 files changed

+769
-1
lines changed

Canny_RISCV/.cproject

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
3+
<storageModule moduleId="org.eclipse.cdt.core.settings">
4+
<cconfiguration id="legup.managedbuild.config.gnu.exe.release.353525777">
5+
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="legup.managedbuild.config.gnu.exe.release.353525777" moduleId="org.eclipse.cdt.core.settings" name="LegUp">
6+
<externalSettings/>
7+
<extensions>
8+
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
9+
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
10+
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
11+
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
12+
</extensions>
13+
</storageModule>
14+
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
15+
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="legup.managedbuild.config.gnu.exe.release.353525777" name="LegUp" parent="legup.managedbuild.config.gnu.exe.release">
16+
<folderInfo id="legup.managedbuild.config.gnu.exe.release.353525777." name="/" resourcePath="">
17+
<toolChain id="legup.managedbuild.toolchain.gnu.exe.release.1446885488" name="Linux GCC" superClass="legup.managedbuild.toolchain.gnu.exe.release">
18+
<targetPlatform id="legup.managedbuild.target.gnu.platform.exe.release.1222145006" name="Debug Platform" superClass="legup.managedbuild.target.gnu.platform.exe.release"/>
19+
<builder buildPath="${workspace_loc:/k}/" id="com.legup.managedbuild.makefileGenerator.1284874661" keepEnvironmentInBuildfile="false" superClass="com.legup.managedbuild.makefileGenerator"/>
20+
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1544502953" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
21+
<tool id="legup.managedbuild.tool.gnu.cpp.compiler.exe.debug.376673803" name="GCC C++ Compiler" superClass="legup.managedbuild.tool.gnu.cpp.compiler.exe.debug">
22+
<option id="gnu.cpp.compiler.option.optimization.level.1759095256" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
23+
<option id="gnu.cpp.compiler.option.debugging.level.1810804837" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
24+
<option id="gnu.cpp.compiler.option.dialect.std.2033344015" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/>
25+
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1733918208" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
26+
</tool>
27+
<tool id="legup.managedbuild.tool.gnu.c.compiler.exe.debug.994173059" name="GCC C Compiler" superClass="legup.managedbuild.tool.gnu.c.compiler.exe.debug">
28+
<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.option.optimization.level.1472888521" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
29+
<option id="gnu.c.compiler.option.debugging.level.254071885" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.none" valueType="enumerated"/>
30+
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.731311993" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
31+
</tool>
32+
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.235767834" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base">
33+
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1347301496" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
34+
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
35+
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
36+
</inputType>
37+
</tool>
38+
<tool id="legup.managedbuild.tool.gnu.cpp.linker.exe.debug.574591359" name="GCC C++ Linker" superClass="legup.managedbuild.tool.gnu.cpp.linker.exe.debug">
39+
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.247544963" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
40+
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
41+
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
42+
</inputType>
43+
</tool>
44+
<tool id="legup.managedbuild.tool.gnu.assembler.exe.debug.457984043" name="GCC Assembler" superClass="legup.managedbuild.tool.gnu.assembler.exe.debug">
45+
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1374461430" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
46+
</tool>
47+
</toolChain>
48+
</folderInfo>
49+
</configuration>
50+
</storageModule>
51+
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
52+
</cconfiguration>
53+
</storageModule>
54+
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
55+
<project id="k.legup.managedbuild.target.gnu.exe.1049438793" name="Executable" projectType="legup.managedbuild.target.gnu.exe"/>
56+
</storageModule>
57+
<storageModule moduleId="scannerConfiguration">
58+
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
59+
<scannerConfigBuildInfo instanceId="legup.managedbuild.config.gnu.exe.release.353525777;legup.managedbuild.config.gnu.exe.release.353525777.;legup.managedbuild.tool.gnu.c.compiler.exe.debug.994173059;cdt.managedbuild.tool.gnu.c.compiler.input.731311993">
60+
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
61+
</scannerConfigBuildInfo>
62+
</storageModule>
63+
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
64+
</cproject>

Canny_RISCV/.project

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>Canny_RISCV</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
10+
<triggers>clean,full,incremental,</triggers>
11+
<arguments>
12+
</arguments>
13+
</buildCommand>
14+
<buildCommand>
15+
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
16+
<triggers>full,incremental,</triggers>
17+
<arguments>
18+
</arguments>
19+
</buildCommand>
20+
</buildSpec>
21+
<natures>
22+
<nature>org.eclipse.cdt.core.cnature</nature>
23+
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
24+
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
25+
<nature>org.eclipse.cdt.core.ccnature</nature>
26+
</natures>
27+
</projectDescription>

Canny_RISCV/Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
########## This file is automatically generated. Any changes to this file will be lost. ##########
2+
########## If you have your own custom Makefile, please name it Makefile.user. ##########
3+
NAME = Canny
4+
LOCAL_CONFIG = -legup-config=config.tcl
5+
SRCS = canny.cpp gaussian_filter.cpp hysteresis_filter.cpp nonmaximum_suppression.cpp sobel_filter.cpp util.cpp
6+
GUI_BASE_DIR =
7+
LEVEL = $(SHLS_ROOT_DIR)/examples
8+
9+
10+
USER_CXX_FLAG += -O3 -pg -Wall -Wno-strict-aliasing -Wno-unused-label -Wno-unknown-pragmas -Wno-attributes -I$(SHLS_ROOT_DIR)/smarthls-library
11+
12+
INPUT_FILES_RISCV += toronto.bmp
13+
OUTPUT_FILES_RISCV += output.bmp
14+
15+
ifneq ("$(wildcard $(GUI_BASE_DIR)Makefile.user)","")
16+
include $(GUI_BASE_DIR)Makefile.user
17+
endif
18+
include $(LEVEL)/Makefile.common
19+

Canny_RISCV/bmp.hpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#ifndef __PPM_H__
2+
#define __PPM_H__
3+
4+
#include "hls/ap_int.hpp"
5+
#include "define.hpp"
6+
7+
using namespace hls;
8+
9+
// bit width of a pixel
10+
const int W = 8;
11+
12+
// 24-bit RGB
13+
typedef ap_uint<3*W> rgb_t;
14+
15+
// 7:0 blue
16+
const int B2 = 0;
17+
const int B1 = B2 + W-1;
18+
19+
// 15:8 green
20+
const int G2 = W;
21+
const int G1 = G2 + W-1;
22+
23+
// 23:16 red
24+
const int R2 = 2*W;
25+
const int R1 = R2 + W-1;
26+
27+
struct input_t {
28+
rgb_t channel1;
29+
rgb_t channel2;
30+
ap_uint<8> alpha;
31+
};
32+
33+
#define SIZE (WIDTH*HEIGHT)
34+
35+
struct bmp_pixel_t {
36+
unsigned char b;
37+
unsigned char g;
38+
unsigned char r;
39+
};
40+
41+
// Total: 54 bytes
42+
struct bmp_header_t {
43+
uint16_t type; // Magic identifier: 0x4d42
44+
uint32_t size; // File size in bytes
45+
uint32_t reserved; // Not used
46+
uint32_t offset; // Offset to image data in bytes from beginning of file (54 bytes)
47+
uint32_t dib_header_size; // DIB Header size in bytes (40 bytes)
48+
int32_t width; // Width of the image
49+
int32_t height; // Height of image
50+
uint16_t num_planes; // Number of color planes
51+
uint16_t bits_per_pixel; // Bits per pixel
52+
uint32_t compression; // Compression type
53+
uint32_t image_size; // Image size in bytes
54+
int32_t x_resolution_ppm; // Pixels per meter
55+
int32_t y_resolution_ppm; // Pixels per meter
56+
uint32_t num_colors; // Number of colors
57+
uint32_t important_colors; // Important colors
58+
} __attribute__((__packed__));
59+
60+
bmp_pixel_t *read_bmp(const char *filename, bmp_header_t *header) {
61+
FILE *file = fopen(filename, "rb");
62+
if (!file) return NULL;
63+
64+
// read BMP header and verify width/height
65+
if (fread(header, sizeof(bmp_header_t), 1, file) != 1) return NULL;
66+
if (header->offset != sizeof(bmp_header_t) ||
67+
header->width != WIDTH || header->height != HEIGHT) return NULL;
68+
69+
// allocate image buffer
70+
bmp_pixel_t *image = (bmp_pixel_t*)malloc(SIZE * sizeof(bmp_pixel_t));
71+
72+
// read BMP image
73+
if (fread(image, sizeof(bmp_pixel_t), SIZE, file) != SIZE) return NULL;
74+
75+
fclose(file);
76+
return image;
77+
}
78+
79+
void write_bmp(const char *filename, const bmp_header_t *header, const bmp_pixel_t *image) {
80+
FILE *file = fopen(filename, "wb");
81+
if (!file) return;
82+
fwrite(header, sizeof(bmp_header_t), 1, file);
83+
fwrite(image, sizeof(bmp_pixel_t), SIZE, file);
84+
fclose(file);
85+
}
86+
87+
#endif

Canny_RISCV/canny.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
2+
#include "define.hpp"
3+
#include "bmp.hpp"
4+
#include "hls/hls_alloc.h"
5+
6+
#include <assert.h>
7+
8+
9+
#ifndef __SYNTHESIS__
10+
// For software, the fifo depth has to be larger
11+
#define FIFO_DEPTH SIZE
12+
#else
13+
#define FIFO_DEPTH 2
14+
#endif
15+
16+
void write_fifo(unsigned char *buf, hls::FIFO<unsigned char> &out_fifo, int nWords) {
17+
#pragma HLS loop pipeline
18+
for(int i=0; i<nWords; i++) {
19+
auto tmp = buf[i];
20+
out_fifo.write(tmp);
21+
}
22+
}
23+
24+
void read_fifo(hls::FIFO<unsigned char> &in_fifo, unsigned char *buf, int nWords) {
25+
#pragma HLS loop pipeline
26+
for(int i=0; i<nWords; i++) {
27+
auto wd = in_fifo.read();
28+
buf[i] = wd;
29+
}
30+
}
31+
32+
33+
void canny(hls::FIFO<unsigned char> &input_fifo,
34+
hls::FIFO<unsigned char> &output_fifo) {
35+
36+
#pragma HLS function dataflow
37+
hls::FIFO<unsigned char> output_fifo_gf(FIFO_DEPTH);
38+
hls::FIFO<unsigned short> output_fifo_sf(FIFO_DEPTH);
39+
hls::FIFO<unsigned char> output_fifo_nm(FIFO_DEPTH);
40+
41+
gaussian_filter(input_fifo, output_fifo_gf);
42+
sobel_filter(output_fifo_gf, output_fifo_sf);
43+
nonmaximum_suppression(output_fifo_sf, output_fifo_nm);
44+
hysteresis_filter(output_fifo_nm, output_fifo);
45+
}
46+
47+
void canny_wrapper(unsigned char *bufIn, unsigned char *bufOut) {
48+
#pragma HLS function top dataflow
49+
#pragma HLS interface default type(axi_target)
50+
#pragma HLS interface argument(bufIn) type(axi_initiator) num_elements(SIZE) max_burst_len(256)
51+
#pragma HLS interface argument(bufOut) type(axi_initiator) num_elements(SIZE) max_burst_len(256)
52+
53+
hls::FIFO<unsigned char> fifo_1(FIFO_DEPTH);
54+
hls::FIFO<unsigned char> fifo_2(FIFO_DEPTH);
55+
write_fifo(bufIn, fifo_1, SIZE);
56+
canny(fifo_1, fifo_2);
57+
read_fifo(fifo_2, bufOut, SIZE);
58+
}
59+
60+
int main() {
61+
bmp_header_t input_channel_header;
62+
bmp_pixel_t *input_channel, *output_channel, *tmp;
63+
64+
input_channel = read_bmp(INPUT_IMAGE, &input_channel_header);
65+
if (!input_channel) return 1;
66+
67+
output_channel = (bmp_pixel_t*)malloc(SIZE * sizeof(bmp_pixel_t));
68+
if (!output_channel) return 1;
69+
70+
unsigned char *bufIn = (unsigned char *)hls_malloc(SIZE);
71+
unsigned char *bufOut = (unsigned char *)hls_malloc(SIZE);
72+
73+
for (int i = 0; i < SIZE; i++) {
74+
unsigned char r = input_channel->r;
75+
unsigned char g = input_channel->g;
76+
unsigned char b = input_channel->b;
77+
unsigned grayscale = (r + g + b) / 3;
78+
bufIn[i] = grayscale;
79+
input_channel++;
80+
}
81+
82+
canny_wrapper(bufIn, bufOut);
83+
84+
tmp = output_channel;
85+
for (int i = 0; i < SIZE; i++) {
86+
tmp->r = bufOut[i];
87+
tmp->g = bufOut[i];
88+
tmp->b = bufOut[i];
89+
tmp++;
90+
}
91+
92+
write_bmp("output.bmp", &input_channel_header, output_channel);
93+
94+
hls_free(bufIn);
95+
hls_free(bufOut);
96+
97+
return 0;
98+
}
99+

Canny_RISCV/config.tcl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
########## This file is automatically generated. Any changes to this file will be lost. ##########
2+
########## If you have your own constraints tcl file, please add it to the project ##########
3+
########## by using the "Set custom config file" constraint in the HLS Constraints dialog. ##########
4+
source $env(SHLS_ROOT_DIR)/examples/legup.tcl
5+
set_project PolarFireSoC MPFS250T Icicle_SoC
6+
7+
set_parameter CLOCK_PERIOD 10

Canny_RISCV/define.hpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef __DEFINE_H__
2+
#define __DEFINE_H__
3+
4+
#include "hls/ap_int.hpp"
5+
#include "hls/streaming.hpp"
6+
7+
// uncomment this line to test on a smaller image for faster co-simulation
8+
//#define FAST_COSIM
9+
10+
#ifdef FAST_COSIM
11+
#define WIDTH 100
12+
#define HEIGHT 56
13+
#define INPUT_IMAGE "toronto_100x56.bmp"
14+
#define GOLDEN_OUTPUT "golden_output_100x56.bmp"
15+
#else
16+
#define WIDTH 1920
17+
#define HEIGHT 1080
18+
#define INPUT_IMAGE "toronto.bmp"
19+
#define GOLDEN_OUTPUT "golden_output.bmp"
20+
#endif
21+
#define SIZE (WIDTH*HEIGHT)
22+
23+
void window_and_line_buffer(hls::ap_uint<10> input,
24+
hls::ap_uint<10> window[3][3]);
25+
26+
// Gaussian Filter.
27+
const unsigned int GF_KERNEL_SIZE = 5;
28+
void gaussian_filter(hls::FIFO<unsigned char> &input_fifo,
29+
hls::FIFO<unsigned char> &output_fifo);
30+
void gf_sw(unsigned char input[][WIDTH], unsigned char output[][WIDTH]);
31+
32+
// Sobel Filter.
33+
const unsigned int SF_KERNEL_SIZE = 3;
34+
void sf_sw(unsigned char input[][WIDTH], hls::ap_uint<10> output[][WIDTH]);
35+
void sobel_filter(hls::FIFO<unsigned char> &input_fifo,
36+
hls::FIFO<unsigned short> &output_fifo);
37+
38+
// Non-maximum suppression.
39+
const unsigned int NM_KERNEL_SIZE = 3;
40+
void nonmaximum_suppression(hls::FIFO<unsigned short> &input_fifo,
41+
hls::FIFO<unsigned char> &output_fifo);
42+
void nm_sw(hls::ap_uint<10> input[][WIDTH], unsigned char output[][WIDTH]);
43+
44+
// Hysteresis filter.
45+
const unsigned int HF_KERNEL_SIZE = 3;
46+
void hf_sw(unsigned char input[][WIDTH], unsigned char output[][WIDTH]);
47+
void hysteresis_filter(hls::FIFO<unsigned char> &input_fifo,
48+
hls::FIFO<unsigned char> &output_fifo);
49+
50+
// Utility functions
51+
bool is_filled(unsigned int kernel_size, unsigned int count);
52+
bool is_out_of_bounds(unsigned int kernel_size, unsigned int i, unsigned int j);
53+
void update_image_position(unsigned int &i, unsigned int &j);
54+
55+
#endif

0 commit comments

Comments
 (0)