diff --git a/.justfile b/.justfile index 7bd57bb..8b38e00 100644 --- a/.justfile +++ b/.justfile @@ -30,7 +30,7 @@ generate: # build default target build: generate - ninja -C ./build/ {{default}} -v + ninja -C ./build/ {{default}} # build all project build-all: generate @@ -38,11 +38,11 @@ build-all: generate # build ISP target build-Visp: generate - cmake --bulid ./build/ -t Visp + ninja -C ./build/ Visp # build ISP Pipeline target build-Visp_Pipeline: generate - cmake --bulid ./build/ -t Visp_Pipeline + ninja -C ./build/ Visp_Pipeline # run default target run: diff --git a/.svlint.toml b/.svlint.toml new file mode 100644 index 0000000..4227f0b --- /dev/null +++ b/.svlint.toml @@ -0,0 +1,105 @@ +option.textwidth = 110 +textrules.style_textwidth = true +textrules.style_semicolon = true +option.indent = 2 +syntaxrules.tab_character = true +syntaxrules.style_indent = true +syntaxrules.multiline_if_begin = true +syntaxrules.multiline_for_begin = true +syntaxrules.style_trailingwhitespace = true +textrules.style_directives = true +syntaxrules.style_operator_arithmetic = true +syntaxrules.style_operator_boolean = true +syntaxrules.style_operator_integer = true +syntaxrules.style_operator_unary = true + +syntaxrules.style_keyword_0or1space = true +syntaxrules.style_keyword_0space = true +syntaxrules.style_keyword_1or2space = true +syntaxrules.style_keyword_construct = true +syntaxrules.style_keyword_datatype = false # Overly restrictive. +syntaxrules.style_keyword_end = true +syntaxrules.style_keyword_new = true +syntaxrules.style_keyword_newline = true +syntaxrules.eventlist_or = true +# Common to **ruleset-simsynth** (a subset of **ruleset-designintent**). +syntaxrules.blocking_assignment_in_always_ff = true +syntaxrules.blocking_assignment_in_always_latch = true +syntaxrules.non_blocking_assignment_in_always_comb = true +syntaxrules.case_default = true +syntaxrules.enum_with_type = true +syntaxrules.function_with_automatic = true +syntaxrules.keyword_forbidden_priority = true +syntaxrules.keyword_forbidden_unique = true +syntaxrules.keyword_forbidden_unique0 = true +syntaxrules.general_always_no_edge = true +syntaxrules.operator_case_equality = true +syntaxrules.procedural_continuous_assignment = true + +# Common to **ruleset-designintent**. +syntaxrules.action_block_with_side_effect = true +syntaxrules.default_nettype_none = true +syntaxrules.function_same_as_system_function = true +syntaxrules.keyword_forbidden_always = true +syntaxrules.keyword_forbidden_wire_reg = true +syntaxrules.module_nonansi_forbidden = true +syntaxrules.localparam_type_twostate = true +syntaxrules.parameter_type_twostate = true +syntaxrules.localparam_explicit_type = true +syntaxrules.parameter_explicit_type = true +syntaxrules.parameter_default_value = true +syntaxrules.parameter_in_generate = true +syntaxrules.parameter_in_package = true +syntaxrules.genvar_declaration_in_loop = true +syntaxrules.genvar_declaration_out_loop = false +syntaxrules.keyword_forbidden_generate = false +syntaxrules.keyword_required_generate = true +syntaxrules.explicit_case_default = true +syntaxrules.explicit_if_else = true +syntaxrules.loop_statement_in_always_comb = true +syntaxrules.loop_statement_in_always_ff = true +syntaxrules.loop_statement_in_always_latch = true +syntaxrules.sequential_block_in_always_comb = true +syntaxrules.sequential_block_in_always_latch = true +syntaxrules.inout_with_tri = true +syntaxrules.input_with_var = true +syntaxrules.output_with_var = true +syntaxrules.interface_port_with_modport = true +option.re_forbidden_checker = ".*" +syntaxrules.re_forbidden_checker = true +option.re_forbidden_class = ".*" +syntaxrules.re_forbidden_class = false +option.re_forbidden_port_ref = ".*" +syntaxrules.re_forbidden_port_ref = true +option.re_forbidden_property = ".*" +syntaxrules.re_forbidden_property = true +option.re_forbidden_sequence = ".*" +syntaxrules.re_forbidden_sequence = true +option.re_forbidden_task = ".*" +syntaxrules.re_forbidden_task = false +syntaxrules.lowercamelcase_package = true +syntaxrules.uppercamelcase_module = true +option.prefix_interface = "ifc_" +syntaxrules.prefix_interface = true +option.prefix_instance = "u_" +syntaxrules.prefix_instance = true +option.prefix_label = "l_" +syntaxrules.generate_case_with_label = true +syntaxrules.generate_for_with_label = true +syntaxrules.generate_if_with_label = true +option.prefix_inout = "b_" +syntaxrules.prefix_inout = true +option.prefix_input = "in_" +syntaxrules.prefix_input = true +option.prefix_output = "out_" +syntaxrules.prefix_output = true +option.re_required_port_interface = "^[a-z]+[a-zA-Z0-9_]*$" +syntaxrules.re_required_port_interface = true +option.re_required_function = "^([a-z]{1,1}[a-z0-9]{0,9}|f_[a-zA-Z0-9_]+)$" +syntaxrules.re_required_function = true +option.re_required_localparam = "^[A-Z]+[A-Z0-9_]*$" +syntaxrules.re_required_localparam = true +option.re_required_parameter = "^[A-Z]+[A-Z0-9_]*$" +syntaxrules.re_required_parameter = true +option.re_required_genvar = "^[a-z]{1,3}$" +syntaxrules.re_required_genvar = true \ No newline at end of file diff --git a/.svls.toml b/.svls.toml new file mode 100644 index 0000000..398f519 --- /dev/null +++ b/.svls.toml @@ -0,0 +1,7 @@ +[verilog] +include_paths = ["rtl/"] +defines = [] +plugins = [] + +[option] +linter = true \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b1a2fc8..0a10cfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,12 @@ find_package(Threads REQUIRED) # Find SystemC using SystemC's CMake integration find_package(SystemCLanguage QUIET) +# Find Spdlog +if(NOT TARGET spdlog) + # Stand-alone build + find_package(spdlog REQUIRED) +endif() + # Create software image process library # file(GLOB_RECURSE IMG_SRC ${PROJECT_SOURCE_DIR}/src/img_process/*.cpp) # add_library(img_process STATIC ${IMG_SRC}) @@ -45,6 +51,8 @@ set(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/logs/) add_compile_definitions( INPUT_IMG="${INPUT_IMG}" OUTPUT_DIR="${OUTPUT_DIR}" + SPDLOG_FMT_EXTERNAL # Fix Error: fmt not found + DEBUG ) # Get RTL source code dir @@ -52,10 +60,11 @@ SUBDIRLIST(RTL_SUBDIR ${PROJECT_SOURCE_DIR}/rtl) # ---------------------- EXE --------------------------- -# VISP +# Visp # ---------------------- EXE --------------------------- add_executable(Visp ${PROJECT_SOURCE_DIR}/src/sc_main.cpp) target_include_directories(Visp PRIVATE ${PROJECT_SOURCE_DIR}/src/img_process) +target_link_libraries(Visp PRIVATE spdlog::spdlog $<$:ws2_32>) # target_link_libraries(Visp PRIVATE img_process) # Add the Verilated circuit to the target @@ -70,7 +79,7 @@ verilate(Visp SYSTEMC COVERAGE TRACE verilator_link_systemc(Visp) # ---------------------- EXE --------------------------- -# VISP_Pipeline +# Visp_Pipeline # ---------------------- EXE --------------------------- add_executable(Visp_Pipeline ${PROJECT_SOURCE_DIR}/src/sc_main_pipeline.cpp) target_include_directories( @@ -78,6 +87,7 @@ target_include_directories( PRIVATE ${PROJECT_SOURCE_DIR}/src/img_process PRIVATE ${PROJECT_SOURCE_DIR}/src ) +target_link_libraries(Visp_Pipeline PRIVATE spdlog::spdlog $<$:ws2_32>) # target_link_libraries(Visp_Pipeline PRIVATE img_process) # Add the Verilated circuit to the target diff --git a/FPGA.nix b/FPGA.nix index c7f7180..31681dc 100644 --- a/FPGA.nix +++ b/FPGA.nix @@ -15,6 +15,9 @@ gcc neocmakelsp clang-tools + + # Libraries + spdlog ]; # Enable languages support diff --git a/flake.lock b/flake.lock index 90b4141..09978ed 100644 --- a/flake.lock +++ b/flake.lock @@ -17,11 +17,11 @@ ] }, "locked": { - "lastModified": 1724232775, - "narHash": "sha256-6u2DycIEgrgNYlLxyGqdFVmBNiKIitnQKJ1pbRP5oko=", + "lastModified": 1726520618, + "narHash": "sha256-jOsaBmJ/EtX5t/vbylCdS7pWYcKGmWOKg4QKUzKr6dA=", "owner": "cachix", "repo": "cachix", - "rev": "03b6cb3f953097bff378fb8b9ea094bd091a4ec7", + "rev": "695525f9086542dfb09fde0871dbf4174abbf634", "type": "github" }, "original": { @@ -77,11 +77,11 @@ "pre-commit-hooks": "pre-commit-hooks_2" }, "locked": { - "lastModified": 1726063457, - "narHash": "sha256-VtMnPqbP2MLJSjEqmGEUb+cTG1dthc+Bfch2/McymbI=", + "lastModified": 1729641677, + "narHash": "sha256-xqZJ10TAw70Zk12XmJ/aKABhE6t4Z/rrf/VdLTxqW00=", "owner": "cachix", "repo": "devenv", - "rev": "39bf6ce569103c9390d37322daa59468c31b3ce7", + "rev": "4f634c92037d3fb7a7cc2feddc4d686ace83b57f", "type": "github" }, "original": { @@ -399,11 +399,11 @@ "pre-commit-hooks": "pre-commit-hooks" }, "locked": { - "lastModified": 1725980365, - "narHash": "sha256-uDwWyizzlQ0HFzrhP6rVp2+2NNA+/TM5zT32dR8GUlg=", + "lastModified": 1727438425, + "narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=", "owner": "domenkozar", "repo": "nix", - "rev": "1e61e9f40673f84c3b02573145492d8af581bec5", + "rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546", "type": "github" }, "original": { @@ -453,11 +453,11 @@ ] }, "locked": { - "lastModified": 1722978926, - "narHash": "sha256-sqOOEaKJJSUFBzag/cGeeXV491TrrVFY3DFBs1w20V8=", + "lastModified": 1729194050, + "narHash": "sha256-ExjfoHbwutLkHAcHGhrem6EcmQ/1+ClCr/0Y9NoPPkk=", "owner": "cachix", "repo": "nixpkgs-python", - "rev": "7c550bca7e6cf95898e32eb2173efe7ebb447460", + "rev": "5e4f20785932a23847191607d84c8806520454f2", "type": "github" }, "original": { @@ -548,11 +548,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1728018373, - "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", + "lastModified": 1729413321, + "narHash": "sha256-I4tuhRpZFa6Fu6dcH9Dlo5LlH17peT79vx1y1SpeKt0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", + "rev": "1997e4aa514312c1af7e2bda7fad1644e778ff26", "type": "github" }, "original": { @@ -639,11 +639,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1725513492, - "narHash": "sha256-tyMUA6NgJSvvQuzB7A1Sf8+0XCHyfSPRx/b00o6K0uo=", + "lastModified": 1726745158, + "narHash": "sha256-D5AegvGoEjt4rkKedmxlSEmC+nNLMBPWFxvmYnVLhjk=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "7570de7b9b504cfe92025dd1be797bf546f66528", + "rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74", "type": "github" }, "original": { diff --git a/rtl/BayerProcess/DPC.sv b/rtl/BayerProcess/DPC.sv index f84d602..202d6e1 100644 --- a/rtl/BayerProcess/DPC.sv +++ b/rtl/BayerProcess/DPC.sv @@ -1,10 +1,11 @@ `timescale 1ns / 1ps - module DPC #( - parameter reg [15:0] TOTAL_WIDTH = 512 + 3, // 总图像宽度 - parameter reg [15:0] TOTAL_HEIGHT = 256 + 3, // 总图像高度 - parameter reg [ 1:0] RAW_TYPE = 3, // (0,0)位置算起RAW_TYPE的值 - parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 + parameter reg [15:0] TOTAL_WIDTH = 512 + 3, // 总图像宽度 + parameter reg [15:0] TOTAL_HEIGHT = 256 + 3, // 总图像高度 + parameter reg [ 1:0] RAW_TYPE = 3, // (0,0)位置算起RAW_TYPE的值 + parameter reg [ 4:0] DATA_WIDTH = 16, // 输入/输出数据位宽 + parameter reg [ 4:0] MODULE_ENABLE = 0, // 是否启用该模块,DEBUG用 + parameter reg [ 4:0] LABLE_ENABLE = 1 // 是否启动坏点标注,DEBUG用 ) ( input wire clk, input wire reset, @@ -220,18 +221,20 @@ module DPC #( channel_cache_correct_final <= channel_cache_correct2[flag_which_dict]; case (flag_which_dict) 2'b00: - flag_if_need_corection <= grad_h_cache2[1] > 4 * (grad_h_cache2[0] + grad_h_cache2[2]); + flag_if_need_corection <= grad_h_cache2[1] / 4 > (grad_h_cache2[0] + grad_h_cache2[2]); 2'b01: - flag_if_need_corection <= grad_v_cache2[1] > 4 * (grad_v_cache2[0] + grad_v_cache2[2]); + flag_if_need_corection <= grad_v_cache2[1] / 4 > (grad_v_cache2[0] + grad_v_cache2[2]); 2'b10: - flag_if_need_corection <= grad_45_cache2[1] > 3 * (grad_45_cache2[0] + grad_45_cache2[2]); + flag_if_need_corection <= grad_45_cache2[1] / 4 > (grad_45_cache2[0] + grad_45_cache2[2]); 2'b11: - flag_if_need_corection <= grad_135_cache2[1] > 3*(grad_135_cache2[0] + grad_135_cache2[2]); + flag_if_need_corection <= grad_135_cache2[1]/4 > (grad_135_cache2[0] + grad_135_cache2[2]); endcase end if(pipeline_valid[7]) begin //如果是坏点,输出计算后的值;如果不是坏点,输出原值 - out_data <= (flag_if_need_corection) ? (channel_cache_correct_final) : (channel_cache4); + if (MODULE_ENABLE) + out_data <= (flag_if_need_corection)?((LABLE_ENABLE)?(12'hFFF):(channel_cache_correct_final)):(channel_cache4); + else out_data <= channel_cache4; end end end @@ -296,3 +299,4 @@ module DPC #( endmodule + diff --git a/rtl/BayerProcess/Demosaic_Pipeline.sv b/rtl/BayerProcess/Demosaic_Pipeline.sv index 1667c48..4b93787 100644 --- a/rtl/BayerProcess/Demosaic_Pipeline.sv +++ b/rtl/BayerProcess/Demosaic_Pipeline.sv @@ -58,7 +58,6 @@ module Demosaic_Pipeline #( raw_type <= RAW_TYPE; end else if (pipeline_running) begin - // First level pipeline for reading data pipeline_valid <= {pipeline_valid[PIPILINE-2:0], in_valid}; if (in_valid) begin @@ -107,7 +106,7 @@ module Demosaic_Pipeline #( end if (pipeline_valid[2]) begin - {out_data[2], out_data[1], out_data[0]} <= {red, blue, green}; + {out_data[2], out_data[1], out_data[0]} <= {red, green, blue}; out_hsync <= (temp_pos_x2 == 0); out_fsync <= ((temp_pos_x2 == 0) && (temp_pos_y2 == 0)); end @@ -119,3 +118,4 @@ module Demosaic_Pipeline #( // grg rgr bgb gbg 258 endmodule + diff --git a/rtl/BayerProcess/Windows.sv b/rtl/BayerProcess/Windows.sv index 4b5b916..6c400c2 100644 --- a/rtl/BayerProcess/Windows.sv +++ b/rtl/BayerProcess/Windows.sv @@ -38,17 +38,21 @@ SHIFT_REG0 -> 1 4 7 . . . . . */ + reg firstframedone; reg [15:0] pos_x, pos_y; always @(posedge clk) begin if (reset) begin pos_x <= 0; pos_y <= 0; + firstframedone <= 0; end else if (regx_out_valid[WINDOWS_WIDTH-2]) begin pos_x <= (pos_x >= IMAGE_WIDTH - 1) ? (0) : (pos_x + 1); pos_y <= (pos_x >= IMAGE_WIDTH - 1)?((pos_y >= IMAGE_HEIGHT - 1)?(0):(pos_y + 1)):(pos_y); + firstframedone <= (pos_x >= IMAGE_WIDTH - 1 && pos_y >= IMAGE_HEIGHT - 1)?(1):(firstframedone); end else begin pos_x <= pos_x; pos_y <= pos_y; + firstframedone <= firstframedone; end end @@ -62,11 +66,13 @@ SHIFT_REG0 -> 1 4 7 . . for (j = 0; j < WINDOWS_WIDTH; j = j + 1) begin if (i == WINDOWS_WIDTH - 1) begin if (j == 0) out_data[(WINDOWS_WIDTH*i)+j] <= regx_out_data[WINDOWS_WIDTH-2]; - else out_data[(WINDOWS_WIDTH*i)+j] <= data_out_shift[j-1][2*i-1]; + else out_data[(WINDOWS_WIDTH*i)+j] <= data_out_shift[j-1][2*j-1]; end else out_data[(WINDOWS_WIDTH*i)+j] <= out_data[(WINDOWS_WIDTH*(i+1))+j]; end end - out_valid <= ~((pos_y <= WINDOWS_WIDTH-WINDOWS_ANCHOR_Y-1 && pos_x < WINDOWS_WIDTH-WINDOWS_ANCHOR_X-1) || (pos_y < WINDOWS_WIDTH-WINDOWS_ANCHOR_Y-1)); + if (firstframedone) out_valid <= 1; + else + out_valid <= ~((pos_y <= WINDOWS_WIDTH-WINDOWS_ANCHOR_Y-1 && pos_x < WINDOWS_WIDTH-WINDOWS_ANCHOR_X-1) || (pos_y < WINDOWS_WIDTH-WINDOWS_ANCHOR_Y-1)); end else begin for (i = 0; i < WINDOWS_WIDTH * WINDOWS_WIDTH - 1; i = i + 1) out_data[i] <= out_data[i]; out_valid <= 0; diff --git a/rtl/Color/ColorBlender_Pipeline.sv b/rtl/Color/ColorBlender_Pipeline.sv index 11eafd9..7d4b2d2 100644 --- a/rtl/Color/ColorBlender_Pipeline.sv +++ b/rtl/Color/ColorBlender_Pipeline.sv @@ -71,9 +71,9 @@ module ColorBlender_Pipeline #( /************* 2:计算2 ************/ if(pipeline_valid[0]) begin if(enable) begin - data_cal1[0] <= (data_cal0[0] * {16'b0, gain_red}) >> 16; + data_cal1[0] <= (data_cal0[0] * {16'b0, gain_blue}) >> 16; data_cal1[1] <= (data_cal0[1] * {16'b0, gain_green}) >> 16; - data_cal1[2] <= (data_cal0[2] * {16'b0, gain_blue}) >> 16; + data_cal1[2] <= (data_cal0[2] * {16'b0, gain_red}) >> 16; end else begin data_cal1[0] <= data_cal0[0] >> 8; data_cal1[1] <= data_cal0[1] >> 8; diff --git a/rtl/Color/GammaCorrection_Pipeline.sv b/rtl/Color/GammaCorrection_Pipeline.sv index f3089d8..13701df 100755 --- a/rtl/Color/GammaCorrection_Pipeline.sv +++ b/rtl/Color/GammaCorrection_Pipeline.sv @@ -1,84 +1,42 @@ `timescale 1ns / 1ps -module GammaCorrection_Pipeline #( - parameter reg [4:0] COLOR_DEPTH = 8 - ) ( - input wire clk, - input wire reset, +module GammaCorrection_Pipeline + import common::*; +#( + parameter bit [4:0] COLOR_DEPTH = 8 +) ( + input var clk, + input var reset, - input wire in_valid, - output reg out_valid, + input var in_ready, + input var in_valid, + input var [COLOR_DEPTH - 1 : 0] in_data[3], - input wire in_ready, - output wire out_ready, + output var out_ready, + output var out_valid, + output var [COLOR_DEPTH - 1 : 0] out_data[3], - input wire in_hsync, - output wire out_hsync, + output var out_hsync, + output var out_fsync, - input wire [COLOR_DEPTH - 1 : 0] in_data[3], + input var [7:0] in_Gtable[256], + input var in_enable +); + Color color; - output reg [COLOR_DEPTH - 1 : 0] out_data[3], + assign out_ready = in_ready; - input wire [7:0] gamma_table[256], - input wire enable - ); - reg [7:0] data_cache[3]; - assign out_ready = (!in_en && state == READ_DATA && !reset) ? 1 : 0; - assign out_receive = (in_en && state == READ_DATA && !reset) ? 1 : 0; - - always @(posedge clk) - begin - if (reset) - begin - out_en <= 0; + always_ff @(posedge clock) begin : blockName + if (reset) begin + out_valid <= 0; out_data[0] <= 0; out_data[1] <= 0; out_data[2] <= 0; + end else begin - data_cache[0] <= 0; - data_cache[1] <= 0; - data_cache[2] <= 0; end - else - begin - case (state) - READ_DATA: - begin - if (in_en) - begin - data_cache[0] <= in_data[0]; - data_cache[1] <= in_data[1]; - data_cache[2] <= in_data[2]; - end - end - SEND_DATA: - begin - if (in_ready && !in_receive) - begin - out_en <= 1; - if (enable) - begin - out_data[0] <= gamma_table[data_cache[0]]; - out_data[1] <= gamma_table[data_cache[1]]; - out_data[2] <= gamma_table[data_cache[2]]; - end - else - begin - out_data[0] <= data_cache[0]; - out_data[1] <= data_cache[1]; - out_data[2] <= data_cache[2]; - end - end - else - out_en <= 0; - end - - default: - ; - endcase - end end diff --git a/rtl/common.sv b/rtl/common.sv new file mode 100644 index 0000000..eaa3e6c --- /dev/null +++ b/rtl/common.sv @@ -0,0 +1,16 @@ +`default_nettype none +package common; + + class Color; + bit [7:0] red; + bit [7:0] green; + bit [7:0] blue; + + function new(bit [7:0] red, bit [7:0] green, bit [7:0] blue); + this.red = red; + this.green = green; + this.blue = blue; + endfunction //new() + endclass //Color + +endpackage diff --git a/rtl/isp_Pipeline.sv b/rtl/isp_Pipeline.sv index c8ac04a..22bd999 100644 --- a/rtl/isp_Pipeline.sv +++ b/rtl/isp_Pipeline.sv @@ -76,10 +76,12 @@ module isp_Pipeline #( ); DPC #( - .TOTAL_WIDTH (IN_WIDTH), - .TOTAL_HEIGHT(IN_HEIGHT), - .RAW_TYPE (3), - .DATA_WIDTH (DATA_WIDTH) + .TOTAL_WIDTH (IN_WIDTH), + .TOTAL_HEIGHT (IN_HEIGHT), + .RAW_TYPE (3), + .DATA_WIDTH (DATA_WIDTH), + .MODULE_ENABLE(1), + .LABLE_ENABLE (1) ) DPC_inst ( .clk (clk), .reset (reset), @@ -113,7 +115,7 @@ module isp_Pipeline #( .WINDOW_LENGTH(3), .TOTAL_WIDTH (IN_WIDTH), .TOTAL_HEIGHT (IN_HEIGHT), - .RAW_TYPE (3), + .RAW_TYPE (0), .DATA_WIDTH (DATA_WIDTH) ) Demosaic_inst ( .clk (clk), diff --git a/src/sc_main.cpp b/src/sc_main.cpp index c06c010..16291e9 100755 --- a/src/sc_main.cpp +++ b/src/sc_main.cpp @@ -21,7 +21,179 @@ // Include model header, generated from Verilating "isp.v" #include "Visp.h" -#include "tb_isp.hpp" + +// Write Pictures +#include "bitmap_image.hpp" + +SC_MODULE(TB_ISP) { + sc_core::sc_in_clk clk; + sc_core::sc_in rst; + + sc_core::sc_in in_ready; // next module ready to receive data + sc_core::sc_out out_valid; // next module data valid signal + sc_core::sc_out out_data[3]; // next module receive data + + sc_core::sc_in in_valid; // this module receive data valid signal + sc_core::sc_out out_ready; // this module ready to receive data + sc_core::sc_in in_data; // this module receive data + + const uint16_t IN_WIDTH; + const uint16_t IN_HEIGHT; + const uint32_t IN_SIZE; + const uint16_t OUT_WIDTH; + const uint16_t OUT_HEIGHT; + const uint32_t OUT_SIZE; + const uint32_t FLAMES; + const std::string OUT_DIR; + + bool is_done; // when receive all data + std::vector image; // the data of image + std::vector process_image; // after isp process, the data of image + + SC_CTOR(TB_ISP, const uint16_t in_width, const uint16_t in_height, + const uint16_t out_width, const uint16_t out_height, + const uint32_t cnt_flame, const std::string& out_dir) + : IN_WIDTH(in_width), IN_HEIGHT(in_height), IN_SIZE(in_width * in_height), + OUT_WIDTH(out_width), OUT_HEIGHT(out_height), + OUT_SIZE(out_width * out_height), FLAMES(cnt_flame), + OUT_DIR(out_dir), + process_image(std::vector(out_width * out_height, 0)) { + SC_CTHREAD(sendData, clk.pos()); // when clk posedge, exec sendData + reset_signal_is(rst, true); // set rst signal + + SC_CTHREAD(readData, clk.pos()); + reset_signal_is(rst, true); // set rst signal + } + + void sendData(void) { + // init var + uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; + bool is_finish = false; // when send all data + // reset + out_valid = false; + for (auto &data : out_data) + data = 0; + + while (true) { + if (in_ready && !is_finish) { + // valid and send data + out_valid = true; + out_data[0] = image[(pos_y + 0) * IN_WIDTH + pos_x]; + out_data[1] = image[(pos_y + 1) * IN_WIDTH + pos_x]; + out_data[2] = image[(pos_y + 2) * IN_WIDTH + pos_x]; + + // print data + std::printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, + image[(pos_y + 0) * IN_WIDTH + pos_x]); + std::printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, + image[(pos_y + 1) * IN_WIDTH + pos_x]); + std::printf("x=%4d, y=%4d, data=0x%04x\n", pos_x, pos_y, + image[(pos_y + 2) * IN_WIDTH + pos_x]); + pos_x++; + + // calculate position and recognize when to finish + if (pos_x >= IN_WIDTH) { + pos_x = 0; + pos_y++; + } + if (pos_y >= IN_HEIGHT - 1) { + pos_y = 0; + cnt_flame++; + } + if (cnt_flame >= FLAMES) { + is_finish = true; + } + } else { + out_valid = false; + } + + // wait for next clk + wait(); + } + } + + void readData(void) { + // init local var + uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; + uint32_t last_data = 0, cnt = 0; + bool is_finish = false; + // reset + out_ready = false; + is_done = false; + + while (true) { + if (!is_finish) { + out_ready = true; + + // when data valid, write it down + if (in_valid) { + process_image[pos_y * OUT_WIDTH + pos_x] = in_data; + + // calculate position + pos_x++; + + if (pos_x >= OUT_WIDTH) { + pos_x = 0; + pos_y++; + } + if (pos_y >= OUT_HEIGHT) { + pos_y = 0; + saveData( + ("output_img_" + std::to_string(cnt_flame) + ".bmp").c_str()); + cnt_flame++; + } + if (cnt_flame >= FLAMES) { + is_finish = true; + } + } + } else { + out_ready = false; + } + + // when no data send, give finish signal + if (is_finish && (last_data == in_data)) { + cnt++; + if (cnt >= 100000L) { // when receive many times the same data + is_done = true; + std::printf("Finish Reading data; pos_x = %d, pos_y = %d\n", pos_x, + pos_y); + } + } else { + cnt = 0; + } + last_data = in_data; + + // wait for next clk + wait(); + } + } + + bool saveData(const char *name) { + bool ret = true; + + // Check Image Size + if (process_image.size() > OUT_SIZE) { + std::cout << "Process Image Over Size!!!\n" + << "Image Size:" << process_image.size() << "\n"; + return false; + } + + // Write BMP image + bitmap_image bmp(OUT_WIDTH, OUT_HEIGHT); + if (!bmp) { + std::cout << "Output Image Open Failed!!!\n"; + return false; + } + for (int y = 0; y < OUT_HEIGHT; y++) + for (int x = 0; x < OUT_WIDTH; x++) + bmp.set_pixel(x, y, + (process_image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16, + (process_image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8, + (process_image[y * OUT_WIDTH + x] & 0x000000ff) >> 0); + bmp.save_image(std::string(OUT_DIR) + name); + return ret; + } +}; // Image Parameters static const uint16_t IN_WIDTH = 1936; diff --git a/src/sc_main_pipeline.cpp b/src/sc_main_pipeline.cpp index a052bb2..1b11f92 100755 --- a/src/sc_main_pipeline.cpp +++ b/src/sc_main_pipeline.cpp @@ -7,8 +7,12 @@ #include // SystemC global header +#include "spdlog/common.h" +#include "spdlog/logger.h" +#include "spdlog/sinks/basic_file_sink.h" #include "sysc/communication/sc_signal.h" #include "sysc/kernel/sc_module.h" +#include #include // Include common routines @@ -24,6 +28,10 @@ // Include testbench written by systemc #include "tb_isp.hpp" +// Spdlog library +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/spdlog.h" + // Image Parameters static const uint16_t IN_WIDTH = 1936; static const uint16_t IN_HEIGHT = 1088; @@ -46,7 +54,7 @@ struct color_gain { double red; double green; double blue; -} color_gain{1.1, 0.7, 1.3}, white_gain; +} color_gain{2, 1, 1}, white_gain; static const double gamma_value = 2.2; static const double sat_inc = 0.5; @@ -56,17 +64,34 @@ using namespace sc_core; using namespace sc_dt; int sc_main(int argc, char *argv[]) { - std::printf("Enter into sc_main\n"); + std::cout << "Enter into sc_main\n"; + + try { + auto logger = std::make_shared( + "sc_main", spdlog::sinks_init_list( + {std::make_shared(), + std::make_shared( + fmt::format("{:s}/ISP.txt", OUTPUT_DIR), true)})); + // When Debug, set Debug level + #ifdef DEBUG + logger->set_level(spdlog::level::debug); + #endif // DEBUG + spdlog::set_default_logger(logger); + spdlog::info("Succeefully init spdlog"); + } catch (const spdlog::spdlog_ex &ex) { + std::cout << "[ERROR] Failed to Init Spdlog!!!\n"; + return -1; + } // Open Image std::ifstream image; image.open(INPUT_IMG, std::ios::in | std::ios::binary); // Check image whether is open if (!image.is_open()) { - std::printf("Open Image Failed!!!\n"); + spdlog::error("Open Image Failed!!!"); exit(0); } else { - std::printf("Open Image Successfully!!!\n"); + spdlog::info("Open Image Successfully!!!\n"); } // Read and Transform Image @@ -84,7 +109,7 @@ int sc_main(int argc, char *argv[]) { // Close and delete image image.close(); delete[] buf; - std::printf("Finish Reading Image\n"); + spdlog::info("Finish Reading Image"); // This is a more complicated example, please also see the simpler // examples/make_hello_c. @@ -207,7 +232,8 @@ int sc_main(int argc, char *argv[]) { VerilatedVcdSc *tfp = nullptr; const char *flag = Verilated::commandArgsPlusMatch("trace"); if (flag && 0 == std::strcmp(flag, "+trace")) { - std::cout << "Enabling waves into logs/vlt_dump.vcd...\n"; + spdlog::info("Enabling waves into logs/vlt_dump.vcd..."); + tfp = new VerilatedVcdSc; isp.trace(tfp, 99); // Trace 99 levels of hierarchy Verilated::mkdir("logs"); @@ -215,7 +241,7 @@ int sc_main(int argc, char *argv[]) { } // Simulate until $finish - std::cout << "Ready to simulate!\n"; + spdlog::info("Ready to simulate!"); 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 diff --git a/src/tb_isp.hpp b/src/tb_isp.hpp index e3578ba..2fde3c9 100644 --- a/src/tb_isp.hpp +++ b/src/tb_isp.hpp @@ -2,17 +2,32 @@ #define __TB_ISP_H__ #include +#include +#include +#include #include // Write Pictures #include "bitmap_image.hpp" +#include "spdlog/common.h" +#include "spdlog/logger.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/spdlog.h" + SC_MODULE(TB_ISP) { + +private: + spdlog::logger log; + spdlog::logger img_log; + +public: sc_core::sc_in_clk clk; sc_core::sc_in rst; - sc_core::sc_in in_ready; // next module ready to receive data - sc_core::sc_out out_valid; // next module data valid signal + sc_core::sc_in in_ready; // next module ready to receive data + sc_core::sc_out out_valid; // next module data valid signal sc_core::sc_out out_data; // next module receive data sc_core::sc_in in_valid; // this module receive data valid signal @@ -34,17 +49,34 @@ SC_MODULE(TB_ISP) { SC_CTOR(TB_ISP, const uint16_t in_width, const uint16_t in_height, const uint16_t out_width, const uint16_t out_height, - const uint32_t cnt_flame, const std::string& out_dir) + const uint32_t cnt_flame, const std::string &out_dir) + // Init class varibles : IN_WIDTH(in_width), IN_HEIGHT(in_height), IN_SIZE(in_width * in_height), OUT_WIDTH(out_width), OUT_HEIGHT(out_height), - OUT_SIZE(out_width * out_height), FLAMES(cnt_flame), - OUT_DIR(out_dir), - process_image(std::vector(out_width * out_height, 0)) { + OUT_SIZE(out_width * out_height), FLAMES(cnt_flame), OUT_DIR(out_dir), + process_image(std::vector(out_width * out_height, 0)), + // Global logger with file and stdout + log("TB_ISP", + spdlog::sinks_init_list( + {std::make_shared(), + std::make_shared( + out_dir + "TB_ISP.txt", true)})), + // Image logger for debug image + img_log("IMG_LOG", std::make_shared( + out_dir + "IMG.txt", true)) { +// When Debug, set Debug level +#ifdef DEBUG + log.set_level(spdlog::level::debug); + img_log.set_level(spdlog::level::debug); +#endif // DEBUG + SC_CTHREAD(sendData, clk.pos()); // when clk posedge, exec sendData reset_signal_is(rst, true); // set rst signal SC_CTHREAD(readData, clk.pos()); reset_signal_is(rst, true); // set rst signal + + log.info("Created TB_ISP Modules"); } void sendData(void) { @@ -62,8 +94,8 @@ SC_MODULE(TB_ISP) { out_data = image[(pos_y + 0) * IN_WIDTH + pos_x]; // print data - std::printf("x=%4d, y=%4d, data=0x%04x\n", pos_x, pos_y, - image[pos_y * IN_WIDTH + pos_x]); + log.debug("x={:4d}, y={:4d}, data=0x{:04x}", pos_x, pos_y, + image[pos_y * IN_WIDTH + pos_x]); pos_x++; // calculate position and recognize when to finish @@ -75,7 +107,7 @@ SC_MODULE(TB_ISP) { pos_y = 0; cnt_flame++; } - if (cnt_flame >= FLAMES) { + if (cnt_flame >= FLAMES + 1) { is_finish = true; } } else { @@ -130,8 +162,8 @@ SC_MODULE(TB_ISP) { cnt++; if (cnt >= 100000L) { // when receive many times the same data is_done = true; - std::printf("Finish Reading data; pos_x = %d, pos_y = %d\n", pos_x, - pos_y); + img_log.info("Finish Reading data; pos_x = {:d}, pos_y = {:d}", pos_x, + pos_y); } } else { cnt = 0; @@ -148,23 +180,34 @@ SC_MODULE(TB_ISP) { // Check Image Size if (process_image.size() > OUT_SIZE) { - std::cout << "Process Image Over Size!!!\n" - << "Image Size:" << process_image.size() << "\n"; + log.error("Image Over Size!!!\nImage Size:{:d}", process_image.size()); return false; } // Write BMP image bitmap_image bmp(OUT_WIDTH, OUT_HEIGHT); if (!bmp) { - std::cout << "Output Image Open Failed!!!\n"; + log.error("Output Image Open Failed!!!"); return false; } - for (int y = 0; y < OUT_HEIGHT; y++) - for (int x = 0; x < OUT_WIDTH; x++) - bmp.set_pixel(x, y, - (process_image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16, - (process_image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8, - (process_image[y * OUT_WIDTH + x] & 0x000000ff) >> 0); + + img_log.info("Image Receive: {:d} Pixels, {:d} Bytes", process_image.size(), + process_image.size() * 3); + + unsigned char red = 0, green = 0, blue = 0; + for (int y = 0; y < OUT_HEIGHT; y++) { + for (int x = 0; x < OUT_WIDTH; x++) { + red = (process_image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16; + green = (process_image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8; + blue = (process_image[y * OUT_WIDTH + x] & 0x000000ff) >> 0; + img_log.debug( + "x={:4d}, y={:4d}, red=0x{:02x}, green=0x{:02x}, blue=0x{:02x}", x, + y, red, green, blue); + + bmp.set_pixel(x, y, red, green, blue); + } + } + bmp.save_image(std::string(OUT_DIR) + name); return ret; } diff --git a/xmake.lua b/xmake.lua index faaeea7..542911d 100644 --- a/xmake.lua +++ b/xmake.lua @@ -2,7 +2,7 @@ add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"}) --- Get C/C++ Lib Path local INCLUDE_DIRS = path.splitenv( - string.vformat("$(env VERILATOR_INCLUDE):$(env SYSTEMC_INCLUDE)") + string.vformat("$(env VERILATOR_INCLUDE):$(env SYSTEMC_INCLUDE):$(env CMAKE_INCLUDE_PATH)") ) target("TB_ISP") @@ -20,4 +20,5 @@ target("TB_ISP") "build/CMakeFiles/Visp.dir/Visp.dir", "src/img_process", INCLUDE_DIRS - ) \ No newline at end of file + ) + add_defines("SPDLOG_FMT_EXTERNAL") \ No newline at end of file