From ee812630dd6e57ddd42165c400cdff3a5757940b Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Tue, 14 May 2024 15:36:54 +0800 Subject: [PATCH] add demosaic testbench using verilator --- Demosaic/sim/Makefile | 2 +- Demosaic/sim/sc_demosaic.cpp | 117 ++++++++++++++++++++++++++++++----- 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/Demosaic/sim/Makefile b/Demosaic/sim/Makefile index 08a9904..f2d8200 100644 --- a/Demosaic/sim/Makefile +++ b/Demosaic/sim/Makefile @@ -89,7 +89,7 @@ run: @echo "-- RUN ---------------------" @rm -rf logs @mkdir -p logs - obj_dir/Vtop +trace + obj_dir/V$(TOP_MODULE) +trace @echo @echo "-- COVERAGE ----------------" diff --git a/Demosaic/sim/sc_demosaic.cpp b/Demosaic/sim/sc_demosaic.cpp index 35e16a8..3be3638 100644 --- a/Demosaic/sim/sc_demosaic.cpp +++ b/Demosaic/sim/sc_demosaic.cpp @@ -5,19 +5,53 @@ #include // Include common routines +#include // mkdir #include #include -#include // mkdir - -// Include model header, generated from Verilating "top.v" +// Include model header, generated from Verilating "demo.v" #include "Vdemosaic2.h" +// Handle file +#include +#include + +#define IM_WIDTH 512 +#define IM_HEIGHT 256 +#define IM_SIZE (IM_WIDTH * IM_HEIGHT) + +using namespace std; using namespace sc_core; using namespace sc_dt; int sc_main(int argc, char* argv[]) { - // This is a more complicated example, please also see the simpler examples/make_hello_c. + // Open image + ifstream in_image; + ofstream out_image; + in_image.open("./transform/test.bin", ios::in | ios::binary); + out_image.open("./transform/out.bin", ios::out | ios::binary); + if (!in_image.is_open()) { + cout << "Open image fail" << endl; + exit(0); + } else { + cout << "Ready to sim" << endl; + } + + // Read image + uint8_t buf[IM_SIZE * 2] = {0}; + in_image.read((char*)buf, IM_SIZE); + in_image.close(); + // Reshape data + uint16_t image[IM_HEIGHT][IM_WIDTH] = {0}; + uint32_t i = 0; + for (int y = 0; y < IM_HEIGHT; y++) { + for (int x = 0; x < IM_WIDTH; x++) { + image[y][x] = (uint16_t)buf[i] + ((uint16_t)buf[i + 1] << 8); + } + } + + // This is a more complicated example, please also see the simpler + // examples/make_hello_c. // Create logs/ directory in case we have traces to put under it Verilated::mkdir("logs"); @@ -30,7 +64,8 @@ int sc_main(int argc, char* argv[]) { // May be overridden by commandArgs argument parsing Verilated::randReset(2); - // Before any evaluation, need to know to calculate those signals only used for tracing + // Before any evaluation, need to know to calculate those signals only used + // for tracing Verilated::traceEverOn(true); // Pass arguments so Verilated code can see them, e.g. $value$plusargs @@ -45,17 +80,33 @@ int sc_main(int argc, char* argv[]) { // Define interconnect sc_signal reset; - sc_signal in_small; + sc_signal in_en; + sc_signal in_que; + sc_signal in_line; + sc_signal data_in[3]; + + sc_signal out_en; + sc_signal out_r, out_g, out_b; // Construct the Verilated model, from inside Vtop.h - // Using unique_ptr is similar to "Vtop* top = new Vtop" then deleting at end - const std::unique_ptr top{new Vdemosaic2{"top"}}; + // Using unique_ptr is similar to "Vtop* top = new Vtop" then deleting at + // end + const std::unique_ptr demo{new Vdemosaic2{"demo"}}; // Attach Vtop's signals to this upper model - top->clk(clk); - top->reset(reset); - + demo->clk(clk); + demo->reset(reset); + demo->data_en(in_en); + demo->data_que(in_que); + demo->data_line(in_line); + demo->data_in[0](data_in[0]); + demo->data_in[1](data_in[1]); + demo->data_in[2](data_in[2]); + demo->out_en(out_en); + demo->out_r(out_r); + demo->out_g(out_g); + demo->out_b(out_b); // You must do one evaluation before enabling waves, in order to allow // SystemC to interconnect everything for testing. @@ -68,22 +119,49 @@ int sc_main(int argc, char* argv[]) { if (flag && 0 == std::strcmp(flag, "+trace")) { std::cout << "Enabling waves into logs/vlt_dump.vcd...\n"; tfp = new VerilatedVcdSc; - top->trace(tfp, 99); // Trace 99 levels of hierarchy + demo->trace(tfp, 99); // Trace 99 levels of hierarchy Verilated::mkdir("logs"); tfp->open("logs/vlt_dump.vcd"); } // Simulate until $finish + uint16_t pos_x = 0, pos_y = 0; + uint32_t out[IM_SIZE] = {0}, out_head = 0; while (!Verilated::gotFinish()) { // Flush the wave files each cycle so we can immediately see the output // Don't do this in "real" programs, do it in an abort() handler instead if (tfp) tfp->flush(); // Apply inputs - if (sc_time_stamp() > sc_time(1, SC_NS) && sc_time_stamp() < sc_time(10, SC_NS)) { - reset_l = !1; // Assert reset + if (sc_time_stamp() < sc_time(10, SC_NS)) { + reset.write(1); // Assert reset } else { - reset_l = !0; // Deassert reset + reset.write(0); // Deassert reset + } + + // Send image data and Read RGB image data + if (sc_time_stamp() > sc_time(10, SC_NS) && clk.posedge()) { + // Send image data to demosaic + if (in_que.read() && pos_y < IM_HEIGHT) { + in_en.write(1); + data_in[0].write(image[pos_y + 0][pos_x++]); + data_in[1].write(image[pos_y + 1][pos_x++]); + data_in[2].write(image[pos_y + 2][pos_x++]); + + if (pos_x >= IM_WIDTH) { + pos_x = 0; + pos_y++; + } + } else { + in_en.write(0); + } + + // Read image data + if (out_en.read()) { + out[out_head++] = ((uint8_t)(out_r.read() * 5 / 12) << 10) + + ((uint8_t)(out_g.read() * 5 / 12) << 5) + + ((uint8_t)(out_b.read() * 5 / 12) << 0); + } } // Simulate 1ns @@ -91,7 +169,7 @@ int sc_main(int argc, char* argv[]) { } // Final model cleanup - top->final(); + demo->final(); // Close trace if opened if (tfp) { @@ -104,6 +182,13 @@ int sc_main(int argc, char* argv[]) { Verilated::mkdir("logs"); VerilatedCov::write("logs/coverage.dat"); #endif + // Save final output image + for (uint32_t i = 0; i < IM_SIZE; i++) { + buf[i * 2] = (out[i] & 0xffff0000) >> 16; + buf[i * 2 + 1] = (out[i] & 0x0000ffff); + } + out_image.write((const char*)buf, 2 * IM_SIZE); + out_image.close(); // Return good completion status return 0;