diff --git a/src/main/resources/cpp/platform-wrapper-tests/GrayScaleFilter.cpp b/src/main/resources/cpp/platform-wrapper-tests/GrayScaleFilter.cpp new file mode 100644 index 0000000..359f664 --- /dev/null +++ b/src/main/resources/cpp/platform-wrapper-tests/GrayScaleFilter.cpp @@ -0,0 +1,87 @@ +#include +#include +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 " <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" <(i, j)[0]; + unsigned char g = image.at(i, j)[1]; + unsigned char r = image.at(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; +} diff --git a/src/main/resources/script/VerilatorMakefile b/src/main/resources/script/VerilatorMakefile index 9856d53..888def4 100644 --- a/src/main/resources/script/VerilatorMakefile +++ b/src/main/resources/script/VerilatorMakefile @@ -3,6 +3,8 @@ 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 @@ -10,6 +12,12 @@ ifeq ($(TRACE),true) 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 diff --git a/src/main/scala/fpgatidbits/Main.scala b/src/main/scala/fpgatidbits/Main.scala index 0553eea..535f274 100644 --- a/src/main/scala/fpgatidbits/Main.scala +++ b/src/main/scala/fpgatidbits/Main.scala @@ -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)} ) diff --git a/src/main/scala/fpgatidbits/examples/ExampleGrayScale.scala b/src/main/scala/fpgatidbits/examples/ExampleGrayScale.scala new file mode 100644 index 0000000..81fbf84 --- /dev/null +++ b/src/main/scala/fpgatidbits/examples/ExampleGrayScale.scala @@ -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 + } +} \ No newline at end of file