Skip to content

Commit

Permalink
Add Grayscale filter example
Browse files Browse the repository at this point in the history
  • Loading branch information
erlingrj committed Sep 4, 2023
1 parent e29c683 commit 310b686
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
87 changes: 87 additions & 0 deletions src/main/resources/cpp/platform-wrapper-tests/GrayScaleFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;

#include "ExampleGrayScale.hpp"
#include "platform.h"

bool Run_ExampleGrayScale(WrapperRegDriver * platform, unsigned char *rgb_image, int rgb_size, unsigned char *grayscale_image) {
ExampleGrayScale t(platform);
int rgb_size_aligned = (rgb_size >> 3) << 3;
int grayscale_size = rgb_size/3;
int grayscale_size_aligned = (grayscale_size >> 3) << 3;
cout << "Signature: " << hex << t.get_signature() << dec << endl;
cout << "Running Grayscale accelerator on image of size " <<rgb_size_aligned <<" Bytes" <<endl;

void * accelBuf = platform->allocAccelBuffer(rgb_size_aligned);
void * accelBufRes = platform->allocAccelBuffer(grayscale_size_aligned);
platform->copyBufferHostToAccel(rgb_image, accelBuf, rgb_size_aligned);

t.set_baseAddr((AccelDblReg) accelBuf);
t.set_resBaseAddr((AccelDblReg) accelBufRes);
t.set_byteCount(rgb_size_aligned);
t.set_resByteCount(grayscale_size_aligned);

t.set_start(1);

cout << "Waiting for Accel" <<endl;
while(t.get_finished() != 1);
cout << "Accel done" <<endl;
unsigned int cc = t.get_cycleCount();
cout << "#cycles = " << cc << " cycles per word = " << endl;
platform->copyBufferAccelToHost(accelBufRes, grayscale_image, grayscale_size_aligned);
t.set_start(0);
return true;
}

int main(int argc, char **argv)
{
if(argc != 2) {
std::cout << "Usage: ./program_name image_path" << std::endl;
return -1;
}

cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR);

if(!image.data) {
std::cout << "Error loading the image" << std::endl;
return -1;
}

int width = image.cols;
int height = image.rows;
int rgb_size = height*width*3;

// Create C-style arrays for the image and grayscale data
unsigned char* rgb_data = new unsigned char[rgb_size];
unsigned char* grayscale_data = new unsigned char[height * width];

int idx_rgb = 0;
int idx_gray = 0;

for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
unsigned char b = image.at<cv::Vec3b>(i, j)[0];
unsigned char g = image.at<cv::Vec3b>(i, j)[1];
unsigned char r = image.at<cv::Vec3b>(i, j)[2];
rgb_data[idx_rgb++] = r;
rgb_data[idx_rgb++] = g;
rgb_data[idx_rgb++] = b;
}
}

WrapperRegDriver * platform = initPlatform();

Run_ExampleGrayScale(platform, rgb_data, rgb_size, grayscale_data);

deinitPlatform(platform);

// Convert the grayscale_data back to a cv::Mat for saving
cv::Mat grayscale_image(height, width, CV_8U, grayscale_data);
cv::imwrite("grayscale_output.jpg", grayscale_image);

delete[] rgb_data;
delete[] grayscale_data;

return 0;
}
8 changes: 8 additions & 0 deletions src/main/resources/script/VerilatorMakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ TRACE ?= false
VERILATOR_SRC_DIR=/usr/share/verilator/include
VERIlATOR_SRC_GEN_DIR=verilated
VERILATOR_OPTIONS=-Iother-verilog -Wno-assignin -Wno-fatal -Wno-lint -Wno-style -Wno-COMBDLY -Wno-STMTDLY
TARGET_LIB=tidbits.a
VER_BUILD_DIR=obj_dir

ifeq ($(TRACE),true)
VERILATOR_OPTIONS += --trace
CC_OPTIONS := -CFLAGS "-DTRACE"
endif

PLATFORM := TesterWrapper
SRCS=main.cpp platform-verilatedtester.cpp

lib: $(SRCS)
verilator --cc $(PLATFORM).v $(VERILATOR_OPTIONS) $(CC_OPTIONS) --exe --build $^
@rm $(VER_BUILD_DIR)/main.o
ar -rcs $(TARGET_LIB) $(VER_BUILD_DIR)/*.o

$(EMULATOR_BIN): main.cpp platform-verilatedtester.cpp
@verilator --cc $(PLATFORM).v $(VERILATOR_OPTIONS) $(CC_OPTIONS) --exe --build main.cpp platform-verilatedtester.cpp
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/fpgatidbits/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ object MainObj {
"ExampleMemLatency" -> {p => new ExampleMemLatency(p)},
"ExampleGather" -> {p => new ExampleGather(p)},
"ExampleSinglePortBRAM" -> {p => new ExampleSinglePortBRAM(p)},
"ExampleGrayScale" -> {p => new ExampleGrayScale(p)},
"HelloAccel" -> {p => new HelloAccel(p)}
)

Expand Down
107 changes: 107 additions & 0 deletions src/main/scala/fpgatidbits/examples/ExampleGrayScale.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package fpgatidbits.examples

import chisel3._
import chisel3.util.{Decoupled, DecoupledIO}
import fpgatidbits.PlatformWrapper._
import fpgatidbits.dma._

class ExampleGrayScaleIO(p: PlatformWrapperParams) extends GenericAcceleratorIF(1, p) {
val start = Input(Bool())
val finished = Output(Bool())
val baseAddr = Input(UInt(64.W))
val byteCount = Input(UInt(32.W))
val resBaseAddr = Input(UInt(64.W))
val resByteCount = Input(UInt(32.W))
val cycleCount = Output(UInt(32.W))
}
// read and sum a contiguous stream of 32-bit uints from main memory
class ExampleGrayScale(p: PlatformWrapperParams) extends GenericAccelerator(p) {
val numMemPorts = 1
val io = IO(new ExampleGrayScaleIO(p))
io.signature := makeDefaultSignature()

val rdP = new StreamReaderParams(
streamWidth = 24, fifoElems = 8, mem = p.toMemReqParams(),
maxBeats = 1, chanID = 0, disableThrottle = true
)

val wrP = new StreamWriterParams(
streamWidth = 8, mem=p.toMemReqParams(), chanID = 0, maxBeats = 1
)

val reader = Module(new StreamReader(rdP)).io
val writer = Module(new StreamWriter(wrP)).io

reader.start := io.start
reader.baseAddr := io.baseAddr
reader.byteCount := io.byteCount
reader.doInit := false.B
reader.initCount := 8.U

writer.start := io.start
writer.baseAddr := io.resBaseAddr
writer.byteCount := io.resByteCount

io.finished := writer.finished

reader.req <> io.memPort(0).memRdReq
io.memPort(0).memRdRsp <> reader.rsp
writer.req <> io.memPort(0).memWrReq
writer.wdat <> io.memPort(0).memWrDat
writer.rsp <> io.memPort(0).memWrRsp

val grayFilter = Module(new GrayScaleFilter)
grayFilter.rgbIn.valid := reader.out.valid
grayFilter.rgbIn.bits := reader.out.bits.asTypeOf(new Colour)
reader.out.ready := grayFilter.rgbIn.ready

grayFilter.grayOut <> writer.in

val regCycleCount = RegInit(0.U(32.W))
io.cycleCount := regCycleCount
when(!io.start) {regCycleCount := 0.U}
.elsewhen(io.start & !io.finished) {regCycleCount := regCycleCount + 1.U}
}

class Colour extends Bundle {
val r = UInt(8.W)
val g = UInt(8.W)
val b = UInt(8.W)
}

class GrayScaleFilter extends Module {
val rgbIn = IO(Flipped(Decoupled(new Colour)))
val grayOut = IO(Decoupled(UInt(8.W)))

val s1_valid = RegInit(false.B)
val s1_r1Shifted = RegInit(0.U(8.W))
val s1_r2Shifted = RegInit(0.U(8.W))
val s1_g1Shifted = RegInit(0.U(8.W))
val s1_g2Shifted = RegInit(0.U(8.W))
val s1_b1Shifted = RegInit(0.U(8.W))
val s1_b2Shifted = RegInit(0.U(8.W))

val s2_valid = RegInit(false.B)
val s2_gray = RegInit(0.U(8.W))

rgbIn.ready := !s2_valid || grayOut.fire
grayOut.valid := s2_valid
grayOut.bits := s2_gray

when(rgbIn.fire) {
// Stage 1
s1_valid := true.B
val rgb = rgbIn.bits
val (r,g,b) = (rgb.r, rgb.g, rgb.b)
s1_r1Shifted := (r >> 2).asUInt
s1_r2Shifted := (r >> 5).asUInt
s1_g1Shifted := (g >> 1).asUInt
s1_g2Shifted := (g >> 4).asUInt
s1_b1Shifted := (b >> 4).asUInt
s1_b2Shifted := (b >> 5).asUInt

// Stage 2
s2_valid := s1_valid
s2_gray := s1_r1Shifted + s1_r2Shifted + s1_g1Shifted + s1_g2Shifted + s1_b1Shifted + s1_b2Shifted
}
}

0 comments on commit 310b686

Please sign in to comment.