forked from custom-computing-ic/dfe-snippets
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
PR design template for image filtering |
28 changes: 28 additions & 0 deletions
28
test/LanguageFeatures/PRImageFilter/src/EdgeLaplaceKernel.maxj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.Kernel; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.KernelParameters; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.types.base.DFEVar; | ||
|
||
public class EdgeLaplaceKernel extends Kernel { | ||
public EdgeLaplaceKernel(KernelParameters parameters, int width) { | ||
super(parameters); | ||
|
||
optimization.pushEnableBitGrowth(true); | ||
|
||
DFEVar inStream = io.input("input", dfeUInt(8)); | ||
|
||
DFEVar window[] = new DFEVar[5]; | ||
window[0] = stream.offset(inStream, -3 * width); | ||
window[1] = stream.offset(inStream, -3); | ||
window[2] = inStream; | ||
window[3] = stream.offset(inStream, 3); | ||
window[4] = stream.offset(inStream, 3 * width); | ||
|
||
DFEVar sum = constant.var(0); | ||
for (int i = 0; i < 5; i++) | ||
sum += (i != 2) ? window[i] : window[i] * -4; | ||
|
||
DFEVar result = sum > 0 ? sum : -sum; | ||
|
||
io.output("output", dfeUInt(8)) <== result.cast(dfeUInt(8)); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
test/LanguageFeatures/PRImageFilter/src/GaussianBlurKernel.maxj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.Kernel; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.KernelParameters; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.types.base.DFEVar; | ||
|
||
public class GaussianBlurKernel extends Kernel{ | ||
|
||
public GaussianBlurKernel(KernelParameters parameters, int width) { | ||
super(parameters); | ||
|
||
optimization.pushEnableBitGrowth(true); | ||
|
||
DFEVar inStream = io.input("input", dfeUInt(8)); | ||
|
||
DFEVar window[] = new DFEVar[9]; | ||
int i = 0; | ||
for (int x = -3; x <= 3; x += 3) { | ||
for (int y = -3; y <= 3; y += 3) { | ||
window[i++] = stream.offset(inStream, x * width + y); | ||
} | ||
} | ||
|
||
DFEVar sum = constant.var(0); | ||
for (int j = 0; j < 9; j++) { | ||
if (j % 2 == 0 && j != 4) | ||
sum += window[j]; | ||
else if (j == 4) | ||
sum += window[j] * 4; | ||
else | ||
sum += window[j] * 2; | ||
} | ||
|
||
DFEVar result = sum / 16; | ||
|
||
io.output("output", dfeUInt(8)) <== result.cast(dfeUInt(8)); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
test/LanguageFeatures/PRImageFilter/src/GrayScaleKernel.maxj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.Kernel; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.KernelParameters; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.types.base.DFEVar; | ||
|
||
public class GrayScaleKernel extends Kernel { | ||
public GrayScaleKernel(KernelParameters parameters) { | ||
super(parameters); | ||
|
||
optimization.pushEnableBitGrowth(true); | ||
|
||
DFEVar inStream = io.input("input", dfeUInt(8)); | ||
|
||
DFEVar countColour = control.count.simpleCounter(2, 3); | ||
|
||
DFEVar r = control.mux(countColour, | ||
inStream, | ||
stream.offset(inStream, -1), | ||
stream.offset(inStream, -2)); | ||
|
||
DFEVar g = control.mux(countColour, | ||
stream.offset(inStream, 1), | ||
inStream, | ||
stream.offset(inStream, -1)); | ||
|
||
DFEVar b = control.mux(countColour, | ||
stream.offset(inStream, 2), | ||
stream.offset(inStream, 1), | ||
inStream); | ||
|
||
DFEVar sum = r + g + b; | ||
|
||
DFEVar result = sum / 3; | ||
|
||
io.output("output", dfeUInt(8)) <== result.cast(dfeUInt(8)); | ||
} | ||
} | ||
|
132 changes: 132 additions & 0 deletions
132
test/LanguageFeatures/PRImageFilter/src/PRImageFilter.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#include <math.h> | ||
#include <stdlib.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include "Maxfiles.h" | ||
#include "MaxSLiCInterface.h" | ||
|
||
extern void max_reconfig_partial_bitstream(max_engine_t *engine, const char* name); | ||
|
||
const char* in_filename = "lena.ppm"; | ||
const char* out_filename = "lena_filtered.ppm"; | ||
const char* golden_filename = "lena_filtered_golden.ppm"; | ||
|
||
|
||
void loadImage(const char *filename, uint8_t **dest, uint64_t *width_out, uint64_t *height_out) | ||
{ | ||
char buffer[128]; | ||
FILE *file = fopen(filename, "r"); | ||
if (file == NULL) | ||
{ | ||
printf("Error opening file %s.", filename); | ||
exit(1); | ||
} | ||
|
||
fgets(buffer, sizeof(buffer), file); // Type | ||
if (strcmp(buffer, "P3\n")) | ||
{ | ||
printf("Error opening file %s. Only P3 format supported", filename); | ||
exit(1); | ||
} | ||
|
||
fgets(buffer, sizeof(buffer), file); // Comment | ||
int width, height; | ||
fscanf(file, "%d %d\n", &width, &height); // Dimensions | ||
if (width != 256 || height != 256) | ||
{ | ||
printf("Image size must be 256x256\n"); | ||
exit(1); | ||
} | ||
|
||
fgets(buffer, sizeof(buffer), file); // Max intensity | ||
|
||
*dest = malloc(width * height * 3); | ||
|
||
for(int i = 0; i < width * height * 3; i++) { | ||
uint8_t v; | ||
fscanf(file, "%hhu", &v); | ||
(*dest)[i] = v; | ||
} | ||
|
||
fclose(file); | ||
|
||
*width_out = width; | ||
*height_out = height; | ||
} | ||
|
||
|
||
void writeImage(const char *filename, uint8_t *data, uint64_t width, uint64_t height) | ||
{ | ||
FILE *file = fopen(filename, "w"); | ||
|
||
fprintf(file, "P3\n"); // Type | ||
fprintf(file, "#generated\n"); // Comment | ||
fprintf(file, "%d %d\n", (int) width, (int) height); // Dimensions | ||
fprintf(file, "255\n"); // Max intensity | ||
|
||
for(uint64_t i = 0; i < width * height * 3; i++) | ||
fprintf(file, "%d\n", data[i]); | ||
|
||
fclose(file); | ||
} | ||
|
||
int checkResult(uint8_t *result) { | ||
uint8_t *golden; | ||
uint64_t width, height; | ||
loadImage(golden_filename, &golden, &width, &height); | ||
|
||
for (uint64_t i = 0; i < width * height; i++) { | ||
if (result[i] != golden[i]) { | ||
free(golden); | ||
return 1; | ||
} | ||
} | ||
|
||
free(golden); | ||
return 0; | ||
} | ||
|
||
int main(void) | ||
{ | ||
printf("Loading image from '%s'\n", in_filename); | ||
uint8_t *in_data; | ||
uint64_t width, height; | ||
loadImage(in_filename, &in_data, &width, &height); | ||
|
||
uint64_t data_size = width * height * 3; | ||
uint8_t *out_data = malloc(data_size); | ||
printf("Configuring DFE with full bitstream\n"); | ||
|
||
max_file_t *maxfile = PRImageFilter_init(); | ||
max_engine_t *engine = max_load(maxfile, "*"); | ||
|
||
printf("Running DFE\n"); | ||
PRImageFilter_actions_t myaction = { data_size, in_data, out_data }; | ||
PRImageFilter_run(engine, &myaction); | ||
|
||
printf("Partially reconfiguring DFE\n"); | ||
max_reconfig_partial_bitstream(engine, "EdgeLaplaceKernel"); | ||
max_reconfig_partial_bitstream(engine, "ThresholdKernel"); | ||
|
||
printf("Running DFE\n"); | ||
myaction.instream_input = out_data; | ||
PRImageFilter_run(engine, &myaction); | ||
|
||
max_unload(engine); | ||
|
||
printf("Saving image to '%s'\n", out_filename); | ||
writeImage(out_filename, out_data, width, height); | ||
|
||
printf("Checking result against '%s'\n", golden_filename); | ||
int ret = checkResult(out_data); | ||
if (!ret) | ||
printf("Result correct\n"); | ||
else | ||
printf("Result incorrect\n"); | ||
|
||
free(in_data); | ||
free(out_data); | ||
|
||
return ret; | ||
} |
75 changes: 75 additions & 0 deletions
75
test/LanguageFeatures/PRImageFilter/src/PRImageFilterManager.maxj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import com.maxeler.maxcompiler.v2.build.EngineParameters; | ||
import com.maxeler.maxcompiler.v2.managers.BuildConfig; | ||
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.CPUTypes; | ||
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.EngineInterface; | ||
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.InterfaceParam; | ||
import com.maxeler.maxcompiler.v2.managers.partial_reconfiguration.PRConfiguration; | ||
import com.maxeler.maxcompiler.v2.managers.partial_reconfiguration.PRManager; | ||
import com.maxeler.maxcompiler.v2.managers.partial_reconfiguration.ReconfigurableBlock; | ||
|
||
public class PRImageFilterManager extends PRManager { | ||
|
||
private final static int s_width = 256; | ||
|
||
public PRImageFilterManager(EngineParameters engineParameters) { | ||
super(engineParameters); | ||
|
||
// Instantiate filter kernels | ||
GrayScaleKernel gray = new GrayScaleKernel(makeKernelParameters("GrayScaleKernel")); | ||
GaussianBlurKernel gauss = new GaussianBlurKernel(makeKernelParameters("GaussianBlurKernel"), s_width); | ||
EdgeLaplaceKernel edge = new EdgeLaplaceKernel(makeKernelParameters("EdgeLaplaceKernel"), s_width); | ||
ThresholdKernel thresh = new ThresholdKernel(makeKernelParameters("ThresholdKernel")); | ||
|
||
// Create block in clock region X0Y8, capable of taking Kernels 'gray' and 'edge' | ||
ReconfigurableBlock block1 = addReconfigurableBlock("block1", 0, 8, 0, 8, gray, edge); | ||
|
||
// Create block in clock region X0Y7, capable of taking Kernels 'gauss' and 'thresh' | ||
ReconfigurableBlock block2 = addReconfigurableBlock("block2", 0, 7, 0, 7, gauss, thresh); | ||
|
||
// Connect streams: CPU --> block1 --> block2 --> CPU | ||
block1.getInput("input") <== addStreamFromCPU("input"); | ||
block2.getInput("input") <== block1.getOutput("output"); | ||
addStreamToCPU("output") <== block2.getOutput("output"); | ||
} | ||
|
||
private static EngineInterface modeDefault() { | ||
EngineInterface engine_interface = new EngineInterface(); | ||
|
||
InterfaceParam N = engine_interface.addParam("N", CPUTypes.UINT64); | ||
engine_interface.setTicks("block1", N); | ||
engine_interface.setTicks("block2", N); | ||
engine_interface.setStream("input", CPUTypes.UINT8, N); | ||
engine_interface.setStream("output", CPUTypes.UINT8, N); | ||
|
||
return engine_interface; | ||
} | ||
|
||
private void configBuild(EngineParameters params) { | ||
BuildConfig buildConfig = getBuildConfig(); | ||
buildConfig.setMPPRCostTableSearchRange(params.getMPPRStartCT(), params.getMPPREndCT()); | ||
buildConfig.setMPPRParallelism(params.getMPPRThreads()); | ||
buildConfig.setMPPRRetryNearMissesThreshold(params.getMPPRRetryThreshold()); | ||
} | ||
|
||
public static void main(String[] args) { | ||
EngineParameters params = new EngineParameters(args); | ||
PRImageFilterManager manager = new PRImageFilterManager(params); | ||
|
||
// Create configuration with GrayScale and GaussianBlur Kernels | ||
PRConfiguration conf1 = new PRConfiguration("conf1"); | ||
conf1.setKernel("block1", "GrayScaleKernel"); | ||
conf1.setKernel("block2", "GaussianBlurKernel"); | ||
|
||
// Create configuration with EdgeLaplace and Threshold Kernels | ||
PRConfiguration conf2 = new PRConfiguration("conf2"); | ||
conf2.setKernel("block1", "EdgeLaplaceKernel"); | ||
conf2.setKernel("block2", "ThresholdKernel"); | ||
|
||
manager.createSLiCinterface(modeDefault()); | ||
manager.configBuild(params); | ||
|
||
// Build with conf1 as the default (initial) configuration | ||
manager.build(conf1, conf2); | ||
} | ||
} | ||
|
22 changes: 22 additions & 0 deletions
22
test/LanguageFeatures/PRImageFilter/src/ThresholdKernel.maxj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.Kernel; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.KernelParameters; | ||
import com.maxeler.maxcompiler.v2.kernelcompiler.types.base.DFEVar; | ||
|
||
public class ThresholdKernel extends Kernel { | ||
private final static int s_min = 0; | ||
private final static int s_max = 255; | ||
private final static int s_thresh = 10; | ||
|
||
public ThresholdKernel(KernelParameters parameters) { | ||
super(parameters); | ||
|
||
DFEVar inStream = io.input("input", dfeUInt(8)); | ||
|
||
DFEVar min = constant.var(dfeUInt(8), s_min); | ||
DFEVar max = constant.var(dfeUInt(8), s_max); | ||
|
||
DFEVar result = (inStream > s_thresh) ? max : min; | ||
|
||
io.output("output", dfeUInt(8)) <== result; | ||
} | ||
} |