diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..972da97 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.29.6) +cmake_policy(SET CMP0074 NEW) + +project(ISP CXX) + +# Add Macro to get all subdir +MACRO(SUBDIRLIST result curdir) + FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) + SET(dirlist "") + FOREACH(child ${children}) + IF(IS_DIRECTORY ${curdir}/${child}) + LIST(APPEND dirlist ${curdir}/${child}) + ENDIF() + ENDFOREACH() + SET(${result} ${dirlist}) +ENDMACRO() + +# Set C++ Standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED true) + +# Find Verilator +find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) +if(NOT verilator_FOUND) + message( + FATAL_ERROR + "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable" + ) +endif() + +# SystemC dependencies +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +# Find SystemC using SystemC's CMake integration +find_package(SystemCLanguage QUIET) + +# Create software image process library +file(GLOB_RECURSE IMG_SRC ${PROJECT_SOURCE_DIR}/src/img_process/*.cpp) +add_library(img_process STATIC ${IMG_SRC}) + +# Create a new executable target +file(GLOB_RECURSE VISP_SRC ${PROJECT_SOURCE_DIR}/src/*.cpp) +add_executable(Visp ${VISP_SRC}) +target_compile_definitions(Visp + PRIVATE INPUT_IMG="${PROJECT_SOURCE_DIR}/src/transform/test.bin" + PRIVATE OUTPUT_DIR="${PROJECT_SOURCE_DIR}/logs/" +) +target_include_directories(Visp PRIVATE ${PROJECT_SOURCE_DIR}/src/img_process) +target_link_libraries(Visp PRIVATE img_process) +# target_compile_features(Visp PUBLIC cxx_std_17) +# set_property(TARGET Visp PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}) + +# Add the Verilated circuit to the target +SUBDIRLIST(RTL_SUBDIR ${PROJECT_SOURCE_DIR}/rtl) +verilate(Visp SYSTEMC COVERAGE TRACE + INCLUDE_DIRS ${RTL_SUBDIR} + VERILATOR_ARGS +librescan +libext+.v+.sv+.vh+.svh -y . -x-assign fast + SOURCES ${PROJECT_SOURCE_DIR}/rtl/isp.sv + TOP_MODULE isp +) + +# SystemC Link +verilator_link_systemc(Visp) diff --git a/FPGA.nix b/FPGA.nix index bd730d8..7f8d0a6 100644 --- a/FPGA.nix +++ b/FPGA.nix @@ -8,11 +8,13 @@ svls # C/C++ - gnumake xmake + gnumake + cmake + ninja gcc + neocmakelsp clang-tools - bear ]; # Enable languages support diff --git a/Makefile b/Makefile deleted file mode 100755 index 4f4622d..0000000 --- a/Makefile +++ /dev/null @@ -1,134 +0,0 @@ -###################################################################### -# -# DESCRIPTION: Verilator Example: Small Makefile -# -# This calls the object directory makefile. That allows the objects to -# be placed in the "current directory" which simplifies the Makefile. -# -# This file ONLY is placed under the Creative Commons Public Domain, for -# any use, without warranty, 2020 by Wilson Snyder. -# SPDX-License-Identifier: CC0-1.0 -# -###################################################################### -# Check for sanity to avoid later confusion - -ifneq ($(words $(CURDIR)),1) - $(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)') -endif - -###################################################################### -# Set up variables - -# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a -# package install, and verilator is in your path. Otherwise find the -# binary relative to $VERILATOR_ROOT (such as when inside the git sources). -ifeq ($(VERILATOR_ROOT),) -VERILATOR = verilator -VERILATOR_COVERAGE = verilator_coverage -else -export VERILATOR_ROOT -VERILATOR = $(VERILATOR_ROOT)/bin/verilator -VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage -endif - -VERILATOR_FLAGS = -# Generate SystemC in executable form -VERILATOR_FLAGS += -sc --exe -# Generate makefile dependencies (not shown as complicates the Makefile) -#VERILATOR_FLAGS += -MMD -# Optimize -VERILATOR_FLAGS += -x-assign fast -# Warn abount lint issues; may not want this on less solid designs -VERILATOR_FLAGS += -Wall -# Make waveforms -VERILATOR_FLAGS += --trace -# Check SystemVerilog assertions -VERILATOR_FLAGS += --assert -# Enable multithreading -VERILATOR_FLAGS += --threads 14 -# Generate coverage analysis -# VERILATOR_FLAGS += --coverage -# Run Verilator in debug mode -#VERILATOR_FLAGS += --debug -# Add this trace to get a backtrace in gdb -#VERILATOR_FLAGS += --gdbbt -# Ignore Some Warnings -VERILATOR_FLAGS += -Wno-WIDTHEXPAND -Wno-UNUSEDSIGNAL -Wno-UNUSEDPARAM - -# Specify top module -TOP_MODULE = isp -VERILATOR_FLAGS += --top-module $(TOP_MODULE) -# Input files for Verilator -# Verilog/SystemVerilog files -SOURCES := $(wildcard ./rtl/isp.sv ./rtl/Windows.sv ./rtl/Demosaic/*.sv ./rtl/Crop/*.sv ./rtl/Color/*.sv) -# C/C++ files -SOURCES += $(wildcard ./src/*.cpp ./src/transform/*.cpp) -# Exclude files -EXCLUDES := $(wildcard ) -VERILATOR_INPUT := $(filter-out $(EXCLUDES), $(SOURCES)) -# Check if SC exists via a verilator call (empty if not) -SYSTEMC_EXISTS := $(shell $(VERILATOR) --get-supported SYSTEMC) - -###################################################################### - -ifneq ($(SYSTEMC_EXISTS),) -default: build run -else -default: nosc -endif - -lint: - @echo "-- Verilator lint check ----" - $(VERILATOR) -sc --lint-only $(VERILATOR_INPUT) - -build: - @echo - @echo "-- VERILATE ----------------" - $(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_INPUT) - - @echo - @echo "-- COMPILE -----------------" -# To compile, we can either -# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above. -# 2. Or, run the make rules Verilator does: -# $(MAKE) -j -C obj_dir -f Vtop.mk -# 3. Or, call a submakefile where we can override the rules ourselves: - $(MAKE) -j -C obj_dir -f V$(TOP_MODULE).mk - -run: - @echo - @echo "-- RUN ---------------------" - obj_dir/V$(TOP_MODULE) - -# @echo -# @echo "-- COVERAGE ----------------" -# @rm -rf logs/annotated -# $(VERILATOR_COVERAGE) --annotate logs/annotated logs/coverage.dat - @echo "-- FINISH ------------------" - -trace: - @rm -rf logs - @mkdir -p logs - obj_dir/V$(TOP_MODULE) +trace - - @echo - @echo "-- DONE --------------------" - @echo "To see waveforms, open vlt_dump.vcd in a waveform viewer" - @echo - - -###################################################################### -# Other targets - -nosc: - @echo - @echo "%Skip: SYSTEMC_INCLUDE not in environment" - @echo "(If you have SystemC see the README, and rebuild Verilator)" - @echo - -show-config: - $(VERILATOR) -V - -maintainer-copy:: -clean mostlyclean distclean maintainer-clean:: - -rm -rf obj_dir logs *.log *.dmp *.vpd coverage.dat core diff --git a/rtl/Color/ColorBlender.sv b/rtl/Color/ColorBlender.sv index 8923678..4a36ba5 100644 --- a/rtl/Color/ColorBlender.sv +++ b/rtl/Color/ColorBlender.sv @@ -1,5 +1,4 @@ -`timescale 1ns / 1ps - +`timescale 1ns/1ps // 三通道图像合成一个RGB图像 module ColorBlender #( parameter reg [4:0] IN_DEPTH = 12, // 输入图像的色深 @@ -7,21 +6,17 @@ module ColorBlender #( ) ( input wire clk, input wire reset, - - input wire [16 - 1:0] in_data [3], - output reg [OUT_DEPTH - 1:0] out_data [3], - - input wire in_valid, - output wire out_valid, - - input wire in_ready, + + input wire in_en, + input wire [15:0] in_data[3], // 0:R 1:G 2:B output wire out_ready, - - input wire in_hsync, - input wire in_fsync, - - output wire out_hsync, - output wire out_fsync, + output wire out_receive, + + // 输出相关 + input wire in_ready, + input wire in_receive, + output reg out_en, + output reg [OUT_DEPTH - 1:0] out_data[3], // 颜色校正 input wire [15:0] gain_red, @@ -29,70 +24,85 @@ module ColorBlender #( input wire [15:0] gain_blue, input wire enable ); + localparam reg [2:0] READ_DATA = 0; + localparam reg [2:0] CALC_DATA = 1; + localparam reg [2:0] SATI_DATA = 2; + localparam reg [2:0] SEND_DATA = 3; - localparam PIPELINE = 4; + reg [2:0] state, nextState; + reg [32 - 1:0] data_cal[3]; // 用于保存运算结果,防止溢出 - reg [PIPELINE-1:0] pipeline_hsync, pipeline_fsync, pipeline_valid; - wire pipeline_flag; - assign pipeline_flag = (pipeline_valid[PIPELINE-1] == 0) | (in_ready); - - //out_ready :只要本模块可以接收数据就一直拉高 - assign out_ready = pipeline_flag; - //out_valid :只要本模块有数据要发送就一直拉高 - assign out_valid = pipeline_valid[PIPELINE-1]; - - assign out_hsync = pipeline_hsync[PIPELINE-1]; - assign out_fsync = pipeline_fsync[PIPELINE-1]; - - reg [32 - 1:0] data_cal0[3]; - reg [32 - 1:0] data_cal1[3]; - reg [32 - 1:0] data_cal2[3]; - - integer i; always @(posedge clk) begin - if(reset) begin - pipeline_valid <= 0; - pipeline_hsync <= 0; - pipeline_fsync <= 0; - for(i=0;i<3;i=i+1) data_cal0[i] <= 0; - for(i=0;i<3;i=i+1) data_cal1[i] <= 0; - for(i=0;i<3;i=i+1) data_cal2[i] <= 0; - for(i=0;i<3;i=i+1) out_data[i] <= 0; - end else if(pipeline_flag) begin - /************* 流水 ************/ - pipeline_valid <= {pipeline_valid[PIPELINE-2:0], in_valid}; - pipeline_hsync <= {pipeline_hsync[PIPELINE-2:0], in_hsync}; - pipeline_fsync <= {pipeline_fsync[PIPELINE-2:0], in_fsync}; - /************* 1:计算1 ************/ - if(in_valid) begin - data_cal0[0] <= ({16'b0, in_data[0]}) << (8 - (IN_DEPTH - OUT_DEPTH)); - data_cal0[1] <= ({16'b0, in_data[1]}) << (8 - (IN_DEPTH - OUT_DEPTH)); - data_cal0[2] <= ({16'b0, in_data[2]}) << (8 - (IN_DEPTH - OUT_DEPTH)); - end - /************* 2:计算2 ************/ - if(pipeline_valid[0]) begin - if(enable) begin - data_cal1[0] <= (data_cal0[0] * {16'b0, gain_red}) >> 16; - data_cal1[1] <= (data_cal0[1] * {16'b0, gain_green}) >> 16; - data_cal1[2] <= (data_cal0[2] * {16'b0, gain_blue}) >> 16; - end else begin - data_cal1[0] <= data_cal0[0] >> 8; - data_cal1[1] <= data_cal0[1] >> 8; - data_cal1[2] <= data_cal0[2] >> 8; + if (reset) begin + state <= READ_DATA; + end else begin + state <= nextState; + end + end + + always @(*) begin + case (state) + READ_DATA: nextState = (in_en) ? CALC_DATA : READ_DATA; + CALC_DATA: nextState = SATI_DATA; + SATI_DATA: nextState = SEND_DATA; + SEND_DATA: nextState = (in_receive) ? READ_DATA : SEND_DATA; + default: nextState = READ_DATA; + endcase + end + + 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 + // 初始化 + data_cal[0] <= 0; + data_cal[1] <= 0; + data_cal[2] <= 0; + + out_data[0] <= 0; + out_data[1] <= 0; + out_data[2] <= 0; + out_en <= 0; + end else begin + case (state) + READ_DATA: begin + if (in_en) begin + data_cal[0] <= ({16'b0, in_data[0]}) << (8 - (IN_DEPTH - OUT_DEPTH)); + data_cal[1] <= ({16'b0, in_data[1]}) << (8 - (IN_DEPTH - OUT_DEPTH)); + data_cal[2] <= ({16'b0, in_data[2]}) << (8 - (IN_DEPTH - OUT_DEPTH)); + end end - end - /************* 3:计算3 ************/ - if(pipeline_valid[1]) begin - data_cal2[0] <= (data_cal1[0][31 : OUT_DEPTH] != 0) ? {32{1'b1}} : data_cal1[0]; - data_cal2[1] <= (data_cal1[1][31 : OUT_DEPTH] != 0) ? {32{1'b1}} : data_cal1[1]; - data_cal2[2] <= (data_cal1[2][31 : OUT_DEPTH] != 0) ? {32{1'b1}} : data_cal1[2]; - end - /************* 4:发送结果 ************/ - if(pipeline_valid[2]) begin - out_data[0] <= data_cal2[0][OUT_DEPTH-1:0]; - out_data[1] <= data_cal2[1][OUT_DEPTH-1:0]; - out_data[2] <= data_cal2[2][OUT_DEPTH-1:0]; - end + + CALC_DATA: begin + if (enable) begin + data_cal[0] <= (data_cal[0] * {16'b0, gain_red}) >> 16; + data_cal[1] <= (data_cal[1] * {16'b0, gain_green}) >> 16; + data_cal[2] <= (data_cal[2] * {16'b0, gain_blue}) >> 16; + end else begin + data_cal[0] <= data_cal[0] >> 8; + data_cal[1] <= data_cal[1] >> 8; + data_cal[2] <= data_cal[2] >> 8; + end + end + + SATI_DATA: begin + data_cal[0] <= |data_cal[0][31 : OUT_DEPTH] ? {32{1'b1}} : data_cal[0]; + data_cal[1] <= |data_cal[1][31 : OUT_DEPTH] ? {32{1'b1}} : data_cal[1]; + data_cal[2] <= |data_cal[2][31 : OUT_DEPTH] ? {32{1'b1}} : data_cal[2]; + end + + SEND_DATA: begin + if (in_ready && !in_receive) begin + out_en <= 1; + out_data[0] <= data_cal[0][OUT_DEPTH-1:0]; + out_data[1] <= data_cal[1][OUT_DEPTH-1:0]; + out_data[2] <= data_cal[2][OUT_DEPTH-1:0]; + end else out_en <= 0; + end + + default: ; + endcase end end diff --git a/rtl/Color/ColorBlender_Pipeline.sv b/rtl/Color/ColorBlender_Pipeline.sv new file mode 100644 index 0000000..8923678 --- /dev/null +++ b/rtl/Color/ColorBlender_Pipeline.sv @@ -0,0 +1,99 @@ +`timescale 1ns / 1ps + +// 三通道图像合成一个RGB图像 +module ColorBlender #( + parameter reg [4:0] IN_DEPTH = 12, // 输入图像的色深 + parameter reg [4:0] OUT_DEPTH = 8 // 输出图像的色深 +) ( + input wire clk, + input wire reset, + + input wire [16 - 1:0] in_data [3], + output reg [OUT_DEPTH - 1:0] out_data [3], + + input wire in_valid, + output wire out_valid, + + input wire in_ready, + output wire out_ready, + + input wire in_hsync, + input wire in_fsync, + + output wire out_hsync, + output wire out_fsync, + + // 颜色校正 + input wire [15:0] gain_red, + input wire [15:0] gain_green, + input wire [15:0] gain_blue, + input wire enable +); + + localparam PIPELINE = 4; + + reg [PIPELINE-1:0] pipeline_hsync, pipeline_fsync, pipeline_valid; + wire pipeline_flag; + assign pipeline_flag = (pipeline_valid[PIPELINE-1] == 0) | (in_ready); + + //out_ready :只要本模块可以接收数据就一直拉高 + assign out_ready = pipeline_flag; + //out_valid :只要本模块有数据要发送就一直拉高 + assign out_valid = pipeline_valid[PIPELINE-1]; + + assign out_hsync = pipeline_hsync[PIPELINE-1]; + assign out_fsync = pipeline_fsync[PIPELINE-1]; + + reg [32 - 1:0] data_cal0[3]; + reg [32 - 1:0] data_cal1[3]; + reg [32 - 1:0] data_cal2[3]; + + integer i; + always @(posedge clk) begin + if(reset) begin + pipeline_valid <= 0; + pipeline_hsync <= 0; + pipeline_fsync <= 0; + for(i=0;i<3;i=i+1) data_cal0[i] <= 0; + for(i=0;i<3;i=i+1) data_cal1[i] <= 0; + for(i=0;i<3;i=i+1) data_cal2[i] <= 0; + for(i=0;i<3;i=i+1) out_data[i] <= 0; + end else if(pipeline_flag) begin + /************* 流水 ************/ + pipeline_valid <= {pipeline_valid[PIPELINE-2:0], in_valid}; + pipeline_hsync <= {pipeline_hsync[PIPELINE-2:0], in_hsync}; + pipeline_fsync <= {pipeline_fsync[PIPELINE-2:0], in_fsync}; + /************* 1:计算1 ************/ + if(in_valid) begin + data_cal0[0] <= ({16'b0, in_data[0]}) << (8 - (IN_DEPTH - OUT_DEPTH)); + data_cal0[1] <= ({16'b0, in_data[1]}) << (8 - (IN_DEPTH - OUT_DEPTH)); + data_cal0[2] <= ({16'b0, in_data[2]}) << (8 - (IN_DEPTH - OUT_DEPTH)); + end + /************* 2:计算2 ************/ + if(pipeline_valid[0]) begin + if(enable) begin + data_cal1[0] <= (data_cal0[0] * {16'b0, gain_red}) >> 16; + data_cal1[1] <= (data_cal0[1] * {16'b0, gain_green}) >> 16; + data_cal1[2] <= (data_cal0[2] * {16'b0, gain_blue}) >> 16; + end else begin + data_cal1[0] <= data_cal0[0] >> 8; + data_cal1[1] <= data_cal0[1] >> 8; + data_cal1[2] <= data_cal0[2] >> 8; + end + end + /************* 3:计算3 ************/ + if(pipeline_valid[1]) begin + data_cal2[0] <= (data_cal1[0][31 : OUT_DEPTH] != 0) ? {32{1'b1}} : data_cal1[0]; + data_cal2[1] <= (data_cal1[1][31 : OUT_DEPTH] != 0) ? {32{1'b1}} : data_cal1[1]; + data_cal2[2] <= (data_cal1[2][31 : OUT_DEPTH] != 0) ? {32{1'b1}} : data_cal1[2]; + end + /************* 4:发送结果 ************/ + if(pipeline_valid[2]) begin + out_data[0] <= data_cal2[0][OUT_DEPTH-1:0]; + out_data[1] <= data_cal2[1][OUT_DEPTH-1:0]; + out_data[2] <= data_cal2[2][OUT_DEPTH-1:0]; + end + end + end + +endmodule diff --git a/rtl/Crop/Crop.sv b/rtl/Crop/Crop.sv index b3afd55..58f40a4 100644 --- a/rtl/Crop/Crop.sv +++ b/rtl/Crop/Crop.sv @@ -1,106 +1,104 @@ -`timescale 1ns / 1ps -module Crop #( - parameter IN_WIDTH = 512, - parameter IN_HEIGHT = 512, - parameter OFFSET_X = 120, - parameter OFFSET_Y = 256, - // parameter TRANSLAYT_X = 120, - // parameter TRANSLAYT_Y = 120, - parameter OUT_WIDTH = 512, - parameter OUT_HEIGHT = 512, - parameter BLANK_COLOR = 6'h000000, - parameter COLOR_DEPTH = 16 -) ( - input wire clk, - input wire reset, - - input wire [COLOR_DEPTH - 1:0] in_data [3], - output reg [COLOR_DEPTH - 1:0] out_data[3], - - input wire in_valid, - output reg out_valid, - - input wire in_ready, - output wire out_ready, - - input wire in_hsync, - input wire in_fsync, - - output reg out_hsync, - output reg out_fsync -); - - localparam PIPILINE = 3; - - reg [PIPILINE-1:0] pipeline_valid; - wire pipeline_running; - assign pipeline_running = in_ready | ~pipeline_valid[PIPILINE-1]; - - reg [31:0] cnt_x, cnt_y, temp_x, temp_y; - reg force_dis, force_en; - reg [COLOR_DEPTH-1:0] data_cache0[3]; - reg [COLOR_DEPTH-1:0] data_cache1[3]; - - //out_ready :只要本模块可以接收数据就一直拉高 - assign out_ready = pipeline_running; - //out_valid :只要本模块可以发出数据就一直拉高 - assign out_valid = (pipeline_valid[PIPILINE-1] & ~force_dis) | force_en; - - //分别表示当前像素: 显示;被裁掉;空。 - reg [1:0] flag_crop; - localparam CROP_ERROR = 2'b00, CROP_KEEP = 2'b01, CROP_GIVE_UP = 2'b10, CROP_BLANK = 2'b11; - - integer i; - always @(posedge clk) begin - if (reset) begin - pipeline_valid <= 0; - cnt_x <= 0; - cnt_y <= 0; - for (i = 0; i < 3; i++) data_cache0[i] <= 0; - for (i = 0; i < 3; i++) data_cache1[i] <= 0; - for (i = 0; i < 3; i++) out_data[i] <= 0; - flag_crop <= 0; - force_dis <= 0; - force_en <= 0; - out_hsync <= 0; - out_fsync <= 0; - temp_x <= 0; - temp_y <= 0; - end else if (pipeline_running) begin - - pipeline_valid <= {pipeline_valid[PIPILINE-2:0], in_valid}; - - if (in_valid) begin //when 00 - for (i = 0; i < 3; i++) data_cache0[i] <= in_data[i]; - cnt_x <= (in_hsync) ? (0) : (cnt_x + 1); - cnt_y <= (in_hsync) ? ((in_fsync) ? (0) : (cnt_y + 1)) : (cnt_y); - end - - if (pipeline_valid[0]) begin //when 00 - for (i = 0; i < 3; i++) data_cache1[i] <= data_cache0[i]; - temp_x <= cnt_x; - temp_y <= cnt_y; - if (cnt_x < OFFSET_X || cnt_y < OFFSET_Y) flag_crop <= CROP_GIVE_UP; - else if (cnt_x < OFFSET_X + OUT_WIDTH && cnt_y < OFFSET_Y + OUT_HEIGHT) begin - if (cnt_x < IN_WIDTH && cnt_y < IN_HEIGHT) flag_crop <= CROP_KEEP; - else flag_crop <= CROP_BLANK; - end else flag_crop <= CROP_ERROR; - end - - if (pipeline_valid[1]) begin - for (i = 0; i < 3; i++) out_data[i] <= data_cache1[i]; - out_hsync <= (temp_x == OFFSET_X) && (temp_y >= OFFSET_Y); - out_fsync <= (temp_x == OFFSET_X) && (temp_y == OFFSET_Y); - case (flag_crop) - CROP_ERROR: {force_dis, force_en} <= {1'b1, 1'b0}; - CROP_KEEP: {force_dis, force_en} <= {1'b0, 1'b0}; - CROP_GIVE_UP: {force_dis, force_en} <= {1'b1, 1'b0}; - CROP_BLANK: - {force_dis, force_en} <= {1'b0, 1'b0}; //应该是01, 但我还没写BLANK逻辑 - endcase - end - end - end - - -endmodule +`timescale 1ns/1ps +module Crop #( + parameter reg [15:0] IN_WIDTH = 1934, + parameter reg [15:0] IN_HEIGHT = 1086, + parameter reg [15:0] OFFSET_X = 7, + parameter reg [15:0] OFFSET_Y = 3, + parameter reg [15:0] OUT_WIDTH = 640, + parameter reg [15:0] OUT_HEIGHT = 480, + parameter reg [4:0] COLOR_DEPTH = 8 +) ( + input wire clk, + input wire reset, + + input wire in_en, + output wire out_ready, + output wire out_receive, + input wire [COLOR_DEPTH - 1:0] in_data[3], + + input wire in_ready, + input wire in_receive, + output reg out_en, + output reg [COLOR_DEPTH - 1:0] out_data[3] +); + reg [1:0] state, nextState; + localparam reg [1:0] READ_DATA = 0; + localparam reg [1:0] HANDLE_DATA = 1; + localparam reg [1:0] SEND_DATA = 2; + + reg [15:0] cnt_x, cnt_y; + reg [COLOR_DEPTH - 1:0] data[3]; + wire is_valid; + + // 状态切换 + always @(posedge clk) begin + if (reset) state <= READ_DATA; + else state <= nextState; + end + + // 下一状态更新 + always @(*) begin + case (state) + READ_DATA: nextState = in_en ? HANDLE_DATA : READ_DATA; + HANDLE_DATA: nextState = SEND_DATA; + SEND_DATA: nextState = (is_valid && !in_receive) ? SEND_DATA : READ_DATA; + default: nextState = READ_DATA; + endcase + end + + assign out_ready = (!in_en && state == READ_DATA && !reset) ? 1 : 0; + assign out_receive = (in_en && state == READ_DATA && !reset) ? 1 : 0; + assign is_valid = ((OFFSET_Y <= cnt_y && cnt_y <= (OFFSET_Y + OUT_HEIGHT - 1)) && + (OFFSET_X <= cnt_x && cnt_x <= (OFFSET_X + OUT_WIDTH))) ? 1 : 0; + + always @(posedge clk) begin + if (reset) begin + cnt_x <= 0; + cnt_y <= 0; + data[0] <= 0; + data[1] <= 0; + data[2] <= 0; + + out_en <= 0; + out_data[0] <= 0; + out_data[1] <= 0; + out_data[2] <= 0; + end else begin + case (state) + READ_DATA: begin + if (in_en) begin + data[0] <= in_data[0]; + data[1] <= in_data[1]; + data[2] <= in_data[2]; + end + end + + HANDLE_DATA: begin + if (cnt_x >= IN_WIDTH - 1) begin + cnt_x <= 0; + cnt_y <= cnt_y + 1; + end else begin + cnt_x <= cnt_x + 1; + end + end + + SEND_DATA: begin + if (cnt_y >= IN_HEIGHT) begin + cnt_y <= 0; + end + + if (in_ready && !in_receive && is_valid) begin + out_en <= 1; + out_data[0] <= data[0]; + out_data[1] <= data[1]; + out_data[2] <= data[2]; + end else out_en <= 0; + end + + default: ; + + endcase + end + end + +endmodule diff --git a/rtl/Crop/Crop_Pipeline.sv b/rtl/Crop/Crop_Pipeline.sv new file mode 100644 index 0000000..b3afd55 --- /dev/null +++ b/rtl/Crop/Crop_Pipeline.sv @@ -0,0 +1,106 @@ +`timescale 1ns / 1ps +module Crop #( + parameter IN_WIDTH = 512, + parameter IN_HEIGHT = 512, + parameter OFFSET_X = 120, + parameter OFFSET_Y = 256, + // parameter TRANSLAYT_X = 120, + // parameter TRANSLAYT_Y = 120, + parameter OUT_WIDTH = 512, + parameter OUT_HEIGHT = 512, + parameter BLANK_COLOR = 6'h000000, + parameter COLOR_DEPTH = 16 +) ( + input wire clk, + input wire reset, + + input wire [COLOR_DEPTH - 1:0] in_data [3], + output reg [COLOR_DEPTH - 1:0] out_data[3], + + input wire in_valid, + output reg out_valid, + + input wire in_ready, + output wire out_ready, + + input wire in_hsync, + input wire in_fsync, + + output reg out_hsync, + output reg out_fsync +); + + localparam PIPILINE = 3; + + reg [PIPILINE-1:0] pipeline_valid; + wire pipeline_running; + assign pipeline_running = in_ready | ~pipeline_valid[PIPILINE-1]; + + reg [31:0] cnt_x, cnt_y, temp_x, temp_y; + reg force_dis, force_en; + reg [COLOR_DEPTH-1:0] data_cache0[3]; + reg [COLOR_DEPTH-1:0] data_cache1[3]; + + //out_ready :只要本模块可以接收数据就一直拉高 + assign out_ready = pipeline_running; + //out_valid :只要本模块可以发出数据就一直拉高 + assign out_valid = (pipeline_valid[PIPILINE-1] & ~force_dis) | force_en; + + //分别表示当前像素: 显示;被裁掉;空。 + reg [1:0] flag_crop; + localparam CROP_ERROR = 2'b00, CROP_KEEP = 2'b01, CROP_GIVE_UP = 2'b10, CROP_BLANK = 2'b11; + + integer i; + always @(posedge clk) begin + if (reset) begin + pipeline_valid <= 0; + cnt_x <= 0; + cnt_y <= 0; + for (i = 0; i < 3; i++) data_cache0[i] <= 0; + for (i = 0; i < 3; i++) data_cache1[i] <= 0; + for (i = 0; i < 3; i++) out_data[i] <= 0; + flag_crop <= 0; + force_dis <= 0; + force_en <= 0; + out_hsync <= 0; + out_fsync <= 0; + temp_x <= 0; + temp_y <= 0; + end else if (pipeline_running) begin + + pipeline_valid <= {pipeline_valid[PIPILINE-2:0], in_valid}; + + if (in_valid) begin //when 00 + for (i = 0; i < 3; i++) data_cache0[i] <= in_data[i]; + cnt_x <= (in_hsync) ? (0) : (cnt_x + 1); + cnt_y <= (in_hsync) ? ((in_fsync) ? (0) : (cnt_y + 1)) : (cnt_y); + end + + if (pipeline_valid[0]) begin //when 00 + for (i = 0; i < 3; i++) data_cache1[i] <= data_cache0[i]; + temp_x <= cnt_x; + temp_y <= cnt_y; + if (cnt_x < OFFSET_X || cnt_y < OFFSET_Y) flag_crop <= CROP_GIVE_UP; + else if (cnt_x < OFFSET_X + OUT_WIDTH && cnt_y < OFFSET_Y + OUT_HEIGHT) begin + if (cnt_x < IN_WIDTH && cnt_y < IN_HEIGHT) flag_crop <= CROP_KEEP; + else flag_crop <= CROP_BLANK; + end else flag_crop <= CROP_ERROR; + end + + if (pipeline_valid[1]) begin + for (i = 0; i < 3; i++) out_data[i] <= data_cache1[i]; + out_hsync <= (temp_x == OFFSET_X) && (temp_y >= OFFSET_Y); + out_fsync <= (temp_x == OFFSET_X) && (temp_y == OFFSET_Y); + case (flag_crop) + CROP_ERROR: {force_dis, force_en} <= {1'b1, 1'b0}; + CROP_KEEP: {force_dis, force_en} <= {1'b0, 1'b0}; + CROP_GIVE_UP: {force_dis, force_en} <= {1'b1, 1'b0}; + CROP_BLANK: + {force_dis, force_en} <= {1'b0, 1'b0}; //应该是01, 但我还没写BLANK逻辑 + endcase + end + end + end + + +endmodule diff --git a/rtl/Demosaic/Demosaic2.sv b/rtl/Demosaic/Demosaic2.sv new file mode 100644 index 0000000..4dde29c --- /dev/null +++ b/rtl/Demosaic/Demosaic2.sv @@ -0,0 +1,187 @@ +`timescale 1ns/1ps +module Demosaic2 #( + parameter reg [15:0] IM_WIDTH = 512, // 图像宽度 + parameter reg [15:0] IM_HEIGHT = 256, // 图像高度 + parameter reg [ 1:0] RAW_TYPE = 3, // 0:grbg 1:rggb 2:bggr 3:gbrg + parameter reg [ 4:0] DATA_SIZE = 16 +) ( + // 基本信号 + input wire clk, + input wire reset, + + // 数据输入信号 + input wire in_en, + input wire [DATA_SIZE - 1:0] in_data [3], // 数据输入线,0、1、2分别表示第一、二、三行 + output wire out_ready, // 数据请求线,高电平:请求三个数据,直到读取完才拉低 + output wire out_receive, + + // en: 输出数据有效信号,高电平有效 + input wire in_ready, + input wire in_receive, + output reg out_en, + output reg [DATA_SIZE - 1:0] out_r, + output reg [DATA_SIZE - 1:0] out_g, + output reg [DATA_SIZE - 1:0] out_b +); + + + // 常量,包括状态机 + // localparam IM_SIZE = IM_HEIGHT * IM_WIDTH; + localparam reg [2:0] READ_DATA = 0; + localparam reg [2:0] COLOR_GEN = 1; + localparam reg [2:0] SEND_DATA = 2; + localparam reg [2:0] SLIDE_WINDOW = 3; + + // 寄存器 + reg [2:0] state, nextState; + reg [15:0] data_cache[9]; // 缓存颜色数据,行列3x3 + reg [15:0] pos_x, pos_y; // 滑动窗口左上角位置 + reg [2:0] cnt_data; // 记录输入数据数量,最大值256 + reg [1:0] raw_type; + reg [15:0] red, blue, green; + + // 三段状态机实现,窗口滑动,颜色计算 + // 状态切换 + always @(posedge clk) begin + if (reset) state <= READ_DATA; + else state <= nextState; + end + + // 下一状态更新 + always @(*) begin + case (state) + // 记录够3x3个数据后,进行rgb转换 + READ_DATA: nextState = (cnt_data >= 3) ? COLOR_GEN : READ_DATA; + COLOR_GEN: nextState = SEND_DATA; + SEND_DATA: nextState = (in_receive) ? SLIDE_WINDOW : SEND_DATA; + SLIDE_WINDOW: nextState = READ_DATA; + default: nextState = READ_DATA; + endcase + end + + // 请求数据 + assign out_ready = (cnt_data <= 2 && !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; + out_r <= 0; + out_g <= 0; + out_r <= 0; + + // 内部寄存器初始化 + pos_x <= 0; + pos_y <= 0; + cnt_data <= 0; + raw_type <= RAW_TYPE; + end else begin + // 状态机执行 + case (state) + // 读取数据 + READ_DATA: begin + if (in_en) begin + data_cache[0 + cnt_data * 3] <= in_data[0]; + data_cache[1 + cnt_data * 3] <= in_data[1]; + data_cache[2 + cnt_data * 3] <= in_data[2]; + + cnt_data <= cnt_data + 1; + end + end + + COLOR_GEN: begin + // 生成rgb图像 + // data case 0 case 1 case 2 case 3 + // 0 3 6 G R G R G R B G B G B G + // 1 4 7 B G B G B G G R G R G R + // 2 5 8 G R G R G R B G B G B G + case (raw_type) + 0: begin // Missing B, R on G + blue <= (data_cache[1] + data_cache[7]) >> 1; + red <= (data_cache[3] + data_cache[5]) >> 1; + green <= data_cache[4]; + end + + 1: begin // Missing G, R on B + green <= (data_cache[1] + data_cache[3] + data_cache[5] + data_cache[7]) >> 2; + red <= (data_cache[0] + data_cache[2] + data_cache[6] + data_cache[8]) >> 2; + blue <= data_cache[4]; + end + + 2: begin // Missing G, B on R + green <= (data_cache[1] + data_cache[3] + data_cache[5] + data_cache[7]) >> 2; + blue <= (data_cache[0] + data_cache[2] + data_cache[6] + data_cache[8]) >> 2; + red <= data_cache[4]; + end + + + 3: begin // Missing B, R on G + red <= (data_cache[1] + data_cache[7]) >> 1; + blue <= (data_cache[3] + data_cache[5]) >> 1; + green <= data_cache[4]; + end + default: ; + endcase + + case (raw_type) + 0: raw_type <= 1; + 1: raw_type <= 0; + 2: raw_type <= 3; + 3: raw_type <= 2; + endcase + end + + SEND_DATA: begin + if (in_ready && !in_receive) begin + out_en <= 1; + out_r <= red; + out_b <= blue; + out_g <= green; + end else out_en <= 0; + end + + SLIDE_WINDOW: begin + // 记录位置寄存器自增,并处理缓存数据 + pos_x <= pos_x + 1; + if (pos_x >= IM_WIDTH - 2 - 1) begin + cnt_data <= 0; + pos_x <= 0; + pos_y <= pos_y + 1; + if (pos_y >= IM_HEIGHT - 2 - 1) begin + pos_y <= 0; + end + // 换行后切换Bayer格式 + if (pos_y % 2 == 1) begin + raw_type <= RAW_TYPE; + end else begin + case (RAW_TYPE) + 0: raw_type <= 2; + 1: raw_type <= 3; + 2: raw_type <= 0; + 3: raw_type <= 1; + default: ; + endcase + end + end else begin + cnt_data <= 2; + + // 窗口右移 + data_cache[0] <= data_cache[3]; + data_cache[1] <= data_cache[4]; + data_cache[2] <= data_cache[5]; + data_cache[3] <= data_cache[6]; + data_cache[4] <= data_cache[7]; + data_cache[5] <= data_cache[8]; + end + end + + default: ; + endcase + end + end + +endmodule + diff --git a/rtl/Demosaic/Demosaic.sv b/rtl/Demosaic/Demosaic_Pipeline.sv similarity index 100% rename from rtl/Demosaic/Demosaic.sv rename to rtl/Demosaic/Demosaic_Pipeline.sv diff --git a/rtl/Windows.sv b/rtl/Demosaic/Windows.sv similarity index 100% rename from rtl/Windows.sv rename to rtl/Demosaic/Windows.sv diff --git a/rtl/isp.sv b/rtl/isp.sv index f83f180..e5d7bde 100644 --- a/rtl/isp.sv +++ b/rtl/isp.sv @@ -1,153 +1,206 @@ -`timescale 1ns / 1ps - -module isp #( - parameter reg [15:0] IN_WIDTH = 1936, - parameter reg [15:0] IN_HEIGHT = 1088, - parameter OFFSET_X = 7, - parameter OFFSET_Y = 3, - parameter reg [15:0] OUT_WIDTH = 1920, - parameter reg [15:0] OUT_HEIGHT = 1080, - parameter reg [ 4:0] COLOR_DEPTH = 8, // Can't Change!!! - parameter reg [ 1:0] RAW_TYPE = 3 // 0:grbg 1:rggb 2:bggr 3:gbrg -) ( - // 基本信号 - input wire clk, - input wire reset, - - // 数据线 - input wire [15:0] in_data[3], // 数据输入线,0、1、2分别表示第一、二、三行 - output wire [3 * COLOR_DEPTH - 1:0] out_data, - - // 数据有效信号 - input wire in_valid, - output wire out_valid, - - // 准备信号 - input wire in_ready, - output wire out_ready, - - // 颜色校正,低八位为小数位,高八位为整数位 - input wire [15:0] gain_red, - input wire [15:0] gain_green, - input wire [15:0] gain_blue, - input wire blender_enable // 是否启用颜色校正 -); - - wire [15:0] Demosaic2_data[3]; - wire [15:0] Windows_data[9]; - wire [COLOR_DEPTH - 1 : 0] Blender_data[3]; - wire [COLOR_DEPTH - 1 : 0] Crop_data[3]; - wire Windows_valid, Demosaic2_valid, Blender_valid, Crop_valid; - wire Windows_ready, Demosaic2_ready, Blender_ready, Crop_ready; - wire Demosaic2_hsync, Blender_hsync, Crop_hsync; - wire Demosaic2_fsync, Blender_fsync, Crop_fsync; - assign out_valid = Crop_valid; - assign out_ready = Windows_ready; - assign out_data = {Crop_data[2], Crop_data[1], Crop_data[0]}; - - Windows #( - .DATA_WIDTH(16) - ) Windows_inst ( - .clk (clk), - .reset (reset), - .in_data (in_data), - .out_data (Windows_data), - .in_valid (in_valid), - .out_valid(Windows_valid), - .in_ready (Demosaic2_ready), - .out_ready(Windows_ready) - ); - - - Demosaic #( - .WINDOW_LENGTH(3), - .TOTAL_WIDTH (IN_WIDTH), - .TOTAL_HEIGHT (IN_HEIGHT), - .RAW_TYPE (RAW_TYPE), - .DATA_WIDTH (16) - ) Demosaic2_inst ( - .clk (clk), - .reset (reset), - .in_data (Windows_data), - .out_data (Demosaic2_data), - .in_valid (Windows_valid), - .out_valid(Demosaic2_valid), - .in_ready (Blender_ready), - .out_ready(Demosaic2_ready), - .out_hsync(Demosaic2_hsync), - .out_fsync(Demosaic2_fsync) - ); - - ColorBlender #( - .IN_DEPTH(12), // 输入图像的色深 - .OUT_DEPTH(COLOR_DEPTH) // 输出图像的色深 - ) ColorBlender_inst ( - .clk (clk), - .reset (reset), - .in_data (Demosaic2_data), - .out_data (Blender_data), - .in_valid (Demosaic2_valid), - .out_valid(Blender_valid), - .in_ready (Crop_ready), - .out_ready(Blender_ready), - .in_hsync (Demosaic2_hsync), - .in_fsync (Demosaic2_fsync), - .out_hsync(Blender_hsync), - .out_fsync(Blender_fsync), - - .gain_red (gain_red), - .gain_green(gain_green), - .gain_blue (gain_blue), - .enable (blender_enable) - ); - - Crop #( - .IN_WIDTH (IN_WIDTH), - .IN_HEIGHT (IN_HEIGHT), - .OFFSET_X (OFFSET_X), - .OFFSET_Y (OFFSET_Y), - .OUT_WIDTH (OUT_WIDTH), - .OUT_HEIGHT (OUT_HEIGHT), - .COLOR_DEPTH(COLOR_DEPTH) - ) Crop_inst ( - .clk (clk), - .reset (reset), - .in_data (Blender_data), - .out_data (Crop_data), - .in_valid (Blender_valid), - .out_valid(Crop_valid), - .in_ready (in_ready), - .out_ready(Crop_ready), - .in_hsync (Blender_hsync), - .in_fsync (Blender_fsync), - .out_hsync(Crop_hsync), - .out_fsync(Crop_fsync) - ); - - // reg [15:0] data_out_temp[8192]; - // reg [31:0] now; - // reg [2:0] cnt_www; - // reg flag_ifdataerror; - - // initial cnt_www = 0; - // always @(posedge reset) begin - // cnt_www <= cnt_www + 1; - // end - - // integer i; - // always @(posedge clk) begin - // if(reset) begin - // flag_ifdataerror <= 0; - // if(cnt_www==1) for(i=0;i<8192;i=i+1) data_out_temp[i] <= 0; - // now <= 0; - // end else if(Crop_valid && in_ready)begin - // now <= now + 1; - // if(cnt_www==1)begin - // if(now<8192) data_out_temp[now] <= Crop_data[0]; - // end else if(cnt_www==2)begin - // flag_ifdataerror <= (data_out_temp[now] != Crop_data[0]); - // end else flag_ifdataerror <= flag_ifdataerror; - // end - // end - -endmodule +`timescale 1ns/1ps +module isp #( + parameter reg [15:0] IN_WIDTH = 1936, + parameter reg [15:0] IN_HEIGHT = 1088, + parameter reg [15:0] OUT_WIDTH = 1920, + parameter reg [15:0] OUT_HEIGHT = 1080, + parameter reg [ 4:0] COLOR_DEPTH = 8, // Can't Change!!! + parameter reg [ 1:0] RAW_TYPE = 3 // 0:grbg 1:rggb 2:bggr 3:gbrg +) ( + // 基本信号 + input wire clk, + input wire reset, + + // 数据输入信号 + input wire in_en, + input wire [15:0] in_data[3], // 数据输入线,0、1、2分别表示第一、二、三行 + output wire out_ready, // 数据请求线,高电平:请求三个数据,直到读取完才拉低 + output wire out_receive, + + // output wire out_clk, + output wire out_en, + output wire [3 * COLOR_DEPTH - 1:0] out_data, + input wire in_ready, + // input wire in_receive, + + // 颜色校正,低八位为小数位,高八位为整数位 + input wire [15:0] gain_red, + input wire [15:0] gain_green, + input wire [15:0] gain_blue, + input wire blender_enable, // 是否启用颜色校正 + + // Gamma矫正,低八位为小数位 + // input wire [7:0] gamma_inverse, + input wire [7:0] gamma_table[256], + input wire gamma_enable, + + // 白平衡 + input wire [15:0] white_gain[3], + input wire [8:0] flame_rate, + input wire white_enable, + + // 饱和度校正 + input wire signed [31:0] saturation_inc, + input wire saturation_enable // -256~256 +); + localparam reg [15:0] BAYER_WIDTH = IN_WIDTH - 2; + localparam reg [15:0] BAYER_HEIGHT = IN_HEIGHT - 2; + + wire [COLOR_DEPTH - 1:0] w_out_data[3]; + assign out_data = {w_out_data[2], w_out_data[1], w_out_data[0]}; + + // 颜色校正,并改变色深 + wire blender_en, blender_ready, blender_receive; + wire [15:0] blender_r, blender_g, blender_b; + + // 裁切图像 + wire crop_en, crop_ready, crop_receive; // scaler 请求数据 + reg [COLOR_DEPTH - 1:0] crop_data[3]; + + // Gamma矫正 + wire gamma_en, gamma_ready, gamma_receive; + wire [COLOR_DEPTH - 1 : 0] gamma_data[3]; + + // 白平衡 + wire white_en, white_ready, white_receive; + wire [COLOR_DEPTH - 1 : 0] white_data[3]; + + // 饱和度校正 + wire saturation_en, saturation_ready, saturation_receive; + wire [COLOR_DEPTH - 1 : 0] saturation_data[3]; + + // reg in_receive; + // always @(posedge clk) in_receive <= in_en; + wire in_receive; + assign in_receive = out_en; + + // assign out_clk = clk; + + Demosaic2 #( + .IM_WIDTH (IN_WIDTH), + .IM_HEIGHT(IN_HEIGHT), + .RAW_TYPE (RAW_TYPE) + ) inst_demosaic ( + .clk(clk), + .reset(reset), + .in_en(in_en), + .in_data(in_data), + .out_ready(out_ready), + .out_receive(out_receive), + + .out_en(blender_en), + .in_ready(blender_ready), + .in_receive(blender_receive), + .out_r(blender_r), + .out_g(blender_g), + .out_b(blender_b) + ); + + ColorBlender #( + .IN_DEPTH (12), + .OUT_DEPTH(COLOR_DEPTH) + ) inst_blender ( + .clk (clk), + .reset(reset), + + .in_en(blender_en), + .in_data({blender_b, blender_g, blender_r}), + .out_ready(blender_ready), + .out_receive(blender_receive), + + .in_ready(crop_ready), + .in_receive(crop_receive), + .out_en(crop_en), + .out_data(crop_data), + + .gain_red(gain_red), + .gain_green(gain_green), + .gain_blue(gain_blue), + .enable(blender_enable) + ); + + Crop #( + .IN_WIDTH(BAYER_WIDTH), + .IN_HEIGHT(BAYER_HEIGHT), + .OUT_WIDTH(OUT_WIDTH), + .OUT_HEIGHT(OUT_HEIGHT), + .COLOR_DEPTH(COLOR_DEPTH) + ) inst_crop ( + .clk (clk), + .reset(reset), + + .in_en(crop_en), + .out_ready(crop_ready), + .out_receive(crop_receive), + .in_data({crop_data[2], crop_data[1], crop_data[0]}), + + .out_en(white_en), + .in_ready(white_ready), + .in_receive(white_receive), + .out_data({white_data[2], white_data[1], white_data[0]}) + ); + + GreyWorld #( + .COLOR_DEPTH(COLOR_DEPTH), + .IM_SIZE({16'b0, OUT_WIDTH} * {16'b0, OUT_HEIGHT}) + ) inst_whitebalance ( + .clk (clk), + .reset(reset), + + .in_en(white_en), + .in_data(white_data), + .out_ready(white_ready), + .out_receive(white_receive), + + .in_ready(gamma_ready), + .in_receive(gamma_receive), + .out_en(gamma_en), + .out_data(gamma_data), + + .enable(white_enable), + .flame_rate(flame_rate), + .white_gain(white_gain) + ); + + // 查找表型Gamma校正 + GammaCorrection #( + .COLOR_DEPTH(COLOR_DEPTH) + ) inst_gamma ( + .clk (clk), + .reset(reset), + + .in_en(gamma_en), + .in_data(gamma_data), + .out_ready(gamma_ready), + .out_receive(gamma_receive), + + .in_ready(saturation_ready), + .in_receive(saturation_receive), + .out_en(saturation_en), + .out_data(saturation_data), + + .gamma_table(gamma_table), + .enable(gamma_enable) + ); + + SaturationCorrection #( + .COLOR_DEPTH(COLOR_DEPTH) + ) inst_saturation ( + .clk (clk), + .reset(reset), + + .in_en(saturation_en), + .out_ready(saturation_ready), + .out_receive(saturation_receive), + .in_data(saturation_data), + + .in_ready(in_ready), + .in_receive(in_receive), + .out_en(out_en), + .out_data(w_out_data), + + .saturation_inc(saturation_inc), + .enable(saturation_enable) + ); + +endmodule diff --git a/rtl/isp_Pipeline.sv b/rtl/isp_Pipeline.sv new file mode 100644 index 0000000..f83f180 --- /dev/null +++ b/rtl/isp_Pipeline.sv @@ -0,0 +1,153 @@ +`timescale 1ns / 1ps + +module isp #( + parameter reg [15:0] IN_WIDTH = 1936, + parameter reg [15:0] IN_HEIGHT = 1088, + parameter OFFSET_X = 7, + parameter OFFSET_Y = 3, + parameter reg [15:0] OUT_WIDTH = 1920, + parameter reg [15:0] OUT_HEIGHT = 1080, + parameter reg [ 4:0] COLOR_DEPTH = 8, // Can't Change!!! + parameter reg [ 1:0] RAW_TYPE = 3 // 0:grbg 1:rggb 2:bggr 3:gbrg +) ( + // 基本信号 + input wire clk, + input wire reset, + + // 数据线 + input wire [15:0] in_data[3], // 数据输入线,0、1、2分别表示第一、二、三行 + output wire [3 * COLOR_DEPTH - 1:0] out_data, + + // 数据有效信号 + input wire in_valid, + output wire out_valid, + + // 准备信号 + input wire in_ready, + output wire out_ready, + + // 颜色校正,低八位为小数位,高八位为整数位 + input wire [15:0] gain_red, + input wire [15:0] gain_green, + input wire [15:0] gain_blue, + input wire blender_enable // 是否启用颜色校正 +); + + wire [15:0] Demosaic2_data[3]; + wire [15:0] Windows_data[9]; + wire [COLOR_DEPTH - 1 : 0] Blender_data[3]; + wire [COLOR_DEPTH - 1 : 0] Crop_data[3]; + wire Windows_valid, Demosaic2_valid, Blender_valid, Crop_valid; + wire Windows_ready, Demosaic2_ready, Blender_ready, Crop_ready; + wire Demosaic2_hsync, Blender_hsync, Crop_hsync; + wire Demosaic2_fsync, Blender_fsync, Crop_fsync; + assign out_valid = Crop_valid; + assign out_ready = Windows_ready; + assign out_data = {Crop_data[2], Crop_data[1], Crop_data[0]}; + + Windows #( + .DATA_WIDTH(16) + ) Windows_inst ( + .clk (clk), + .reset (reset), + .in_data (in_data), + .out_data (Windows_data), + .in_valid (in_valid), + .out_valid(Windows_valid), + .in_ready (Demosaic2_ready), + .out_ready(Windows_ready) + ); + + + Demosaic #( + .WINDOW_LENGTH(3), + .TOTAL_WIDTH (IN_WIDTH), + .TOTAL_HEIGHT (IN_HEIGHT), + .RAW_TYPE (RAW_TYPE), + .DATA_WIDTH (16) + ) Demosaic2_inst ( + .clk (clk), + .reset (reset), + .in_data (Windows_data), + .out_data (Demosaic2_data), + .in_valid (Windows_valid), + .out_valid(Demosaic2_valid), + .in_ready (Blender_ready), + .out_ready(Demosaic2_ready), + .out_hsync(Demosaic2_hsync), + .out_fsync(Demosaic2_fsync) + ); + + ColorBlender #( + .IN_DEPTH(12), // 输入图像的色深 + .OUT_DEPTH(COLOR_DEPTH) // 输出图像的色深 + ) ColorBlender_inst ( + .clk (clk), + .reset (reset), + .in_data (Demosaic2_data), + .out_data (Blender_data), + .in_valid (Demosaic2_valid), + .out_valid(Blender_valid), + .in_ready (Crop_ready), + .out_ready(Blender_ready), + .in_hsync (Demosaic2_hsync), + .in_fsync (Demosaic2_fsync), + .out_hsync(Blender_hsync), + .out_fsync(Blender_fsync), + + .gain_red (gain_red), + .gain_green(gain_green), + .gain_blue (gain_blue), + .enable (blender_enable) + ); + + Crop #( + .IN_WIDTH (IN_WIDTH), + .IN_HEIGHT (IN_HEIGHT), + .OFFSET_X (OFFSET_X), + .OFFSET_Y (OFFSET_Y), + .OUT_WIDTH (OUT_WIDTH), + .OUT_HEIGHT (OUT_HEIGHT), + .COLOR_DEPTH(COLOR_DEPTH) + ) Crop_inst ( + .clk (clk), + .reset (reset), + .in_data (Blender_data), + .out_data (Crop_data), + .in_valid (Blender_valid), + .out_valid(Crop_valid), + .in_ready (in_ready), + .out_ready(Crop_ready), + .in_hsync (Blender_hsync), + .in_fsync (Blender_fsync), + .out_hsync(Crop_hsync), + .out_fsync(Crop_fsync) + ); + + // reg [15:0] data_out_temp[8192]; + // reg [31:0] now; + // reg [2:0] cnt_www; + // reg flag_ifdataerror; + + // initial cnt_www = 0; + // always @(posedge reset) begin + // cnt_www <= cnt_www + 1; + // end + + // integer i; + // always @(posedge clk) begin + // if(reset) begin + // flag_ifdataerror <= 0; + // if(cnt_www==1) for(i=0;i<8192;i=i+1) data_out_temp[i] <= 0; + // now <= 0; + // end else if(Crop_valid && in_ready)begin + // now <= now + 1; + // if(cnt_www==1)begin + // if(now<8192) data_out_temp[now] <= Crop_data[0]; + // end else if(cnt_www==2)begin + // flag_ifdataerror <= (data_out_temp[now] != Crop_data[0]); + // end else flag_ifdataerror <= flag_ifdataerror; + // end + // end + +endmodule diff --git a/rtl/isp_tb.sv b/rtl/isp_Pipeline_tb.sv similarity index 100% rename from rtl/isp_tb.sv rename to rtl/isp_Pipeline_tb.sv diff --git a/src/img_process/bmp.cpp b/src/img_process/bmp.cpp new file mode 100755 index 0000000..93521d2 --- /dev/null +++ b/src/img_process/bmp.cpp @@ -0,0 +1,87 @@ +#include "bmp.hpp" + +#include + +// 将RGB24格式像素数据封装为BMP图像 +bool write_bmp(const char *filename, uint8_t *data, int32_t width, + int32_t height) { + BMPFileHeader file_header = {0}; + BMPInfoHeader info_header = {0}; + std::ofstream ofs(filename, std::ios::binary); + if (!ofs) { + std::cerr << "Failed to create file: " << filename << std::endl; + return false; + } + // BMP文件头 + file_header.type = 0x4D42; // BM + file_header.size = + sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + width * height * 3; + file_header.offset = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader); + ofs.write(reinterpret_cast(&file_header), sizeof(file_header)); + + // BMP位图信息头 + info_header.size = sizeof(BMPInfoHeader); + info_header.width = width; + info_header.height = height; + info_header.planes = 1; + info_header.bit_count = 24; + info_header.size_image = width * height * 3; + ofs.write(reinterpret_cast(&info_header), sizeof(info_header)); + + // 像素数据 + int32_t row_size = (((width + 1) * 3) / 4) * 4; // 行字节数,必须为4的倍数 + uint8_t *row_data = new uint8_t[row_size]; + for (int32_t y = height - 1; y >= 0; --y) { // BMP图像的行是从下往上存储的 + for (int32_t x = 0; x < width; ++x) { + row_data[x * 3 + 2] = data[(y * width + x) * 3 + 0]; // B + row_data[x * 3 + 1] = data[(y * width + x) * 3 + 1]; // G + row_data[x * 3 + 0] = data[(y * width + x) * 3 + 2]; // R + } + ofs.write(reinterpret_cast(row_data), row_size); + } + delete[] row_data; + ofs.close(); + return true; +} + +bool writeBMP(std::ofstream &pic_file, std::vector &pic_data, + const int32_t pic_width, const int32_t pic_height) { + BMPFileHeader file_header = {0}; + BMPInfoHeader info_header = {0}; + + // Check file + if (!pic_file || !pic_file.is_open()) { + std::printf("Failed to open file!\n"); + return false; + } + + // Write file header + file_header.type = 0x4D42; // BM + file_header.size = + sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + pic_width * pic_height * 3; + file_header.offset = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader); + pic_file.write(reinterpret_cast(&file_header), sizeof(file_header)); + + // Write info header + info_header.size = sizeof(BMPInfoHeader); + info_header.width = pic_width; + info_header.height = pic_height; + info_header.planes = 1; + info_header.bit_count = 24; + info_header.size_image = pic_width * pic_height * 3; + pic_file.write(reinterpret_cast(&info_header), sizeof(info_header)); + + // Write BMP + int32_t row_size = (((pic_width + 1) * 3) / 4) * 4; // 行字节数,必须为4的倍数 + uint8_t *row_data = new uint8_t[row_size]; + for (int32_t y = pic_height - 1; y >= 0; --y) { // BMP图像的行是从下往上存储的 + for (int32_t x = 0; x < pic_width; ++x) { + row_data[x * 3 + 2] = pic_data[(y * pic_width + x) * 3 + 0]; // B + row_data[x * 3 + 1] = pic_data[(y * pic_width + x) * 3 + 1]; // G + row_data[x * 3 + 0] = pic_data[(y * pic_width + x) * 3 + 2]; // R + } + pic_file.write(reinterpret_cast(row_data), row_size); + } + delete[] row_data; + return true; +} \ No newline at end of file diff --git a/src/img_process/bmp.hpp b/src/img_process/bmp.hpp new file mode 100755 index 0000000..76824b4 --- /dev/null +++ b/src/img_process/bmp.hpp @@ -0,0 +1,43 @@ +#ifndef __BMP_H__ +#define __BMP_H__ + +#include +#include +#include +#include +#include + +#pragma pack(push, 1) // 1字节对齐 + +// BMP文件头结构体 +struct BMPFileHeader { + uint16_t type; // 文件类型,必须为"BM" + uint32_t size; // 文件大小,单位为字节 + uint16_t reserved1; // 保留字段,必须为0 + uint16_t reserved2; // 保留字段,必须为0 + uint32_t offset; // 像素数据起始位置,单位为字节 +}; + +// BMP位图信息头结构体 +struct BMPInfoHeader { + uint32_t size; // 信息头大小,必须为40 + int32_t width; // 图像宽度,单位为像素 + int32_t height; // 图像高度,单位为像素 + uint16_t planes; // 颜色平面数,必须为1 + uint16_t bit_count; // 每个像素的位数,必须为24 + uint32_t compression; // 压缩方式,必须为0 + uint32_t size_image; // 像素数据大小,单位为字节 + int32_t x_pels_per_meter; // X方向像素数/米 + int32_t y_pels_per_meter; // Y方向像素数/米 + uint32_t clr_used; // 使用的颜色数,必须为0 + uint32_t clr_important; // 重要的颜色数,必须为0 +}; + +#pragma pack(pop) + +bool write_bmp(const char *filename, uint8_t *data, int32_t width, + int32_t height); +bool writeBMP(std::ofstream &pic_file, std::vector &pic_data, + const int32_t pic_width, const int32_t pic_height); + +#endif \ No newline at end of file diff --git a/src/pic_process/demosaic.cpp b/src/img_process/demosaic.cpp.bak similarity index 100% rename from src/pic_process/demosaic.cpp rename to src/img_process/demosaic.cpp.bak diff --git a/src/pic_process/demosaic2.cpp b/src/img_process/demosaic2.cpp.bak similarity index 100% rename from src/pic_process/demosaic2.cpp rename to src/img_process/demosaic2.cpp.bak diff --git a/src/sc_main.cpp b/src/sc_main.cpp index 4c92357..868db84 100644 --- a/src/sc_main.cpp +++ b/src/sc_main.cpp @@ -5,19 +5,509 @@ #include // Include common routines -#include // mkdir +#include // mkdir #include #include // Include model header, generated from Verilating "isp.v" -#include "obj_dir/Visp.h" -#include "tb_isp.hpp" +#include "Visp.h" -// Read/Write Files +// Handle file #include #include -int sc_main(int argc, const char** argv) { +// math +#include - return 0; -} \ No newline at end of file +#include "bmp.hpp" + +static const uint16_t IN_WIDTH = 1936; +static const uint16_t IN_HEIGHT = 1088; +static const uint32_t IN_SIZE = (IN_WIDTH * IN_HEIGHT); +static const uint16_t OUT_WIDTH = 1920; +static const uint16_t OUT_HEIGHT = 1080; +static const uint32_t OUT_SIZE = (OUT_WIDTH * OUT_HEIGHT); +static const uint32_t FLAMES = 2; + +// Input image path and Output directory path +#ifndef INPUT_IMG +const char *INPUT_IMG = "./src/transform/test.bin"; +#endif +#ifndef OUTPUT_DIR +const char *OUTPUT_DIR = "./logs/"; +#endif + +// color gain for correcting color +struct color_gain { + double red; + double green; + double blue; +} color_gain{1.1, 0.7, 1.3}, white_gain; + +static const double gamma_value = 2.2; +static const double saturation_inc = 0.5; +static const double contrast = 1.2; +// static const double white_radio = 0.1; + +using namespace sc_core; +using namespace sc_dt; + +bool picProcess(uint32_t *image, uint16_t number); + +SC_MODULE(TB_ISP) { + sc_in_clk clk; + sc_in reset; + + sc_in in_ready; + sc_in in_receive; + sc_out out_en; + sc_out out_data[3]; + + sc_in im_en; + sc_out out_ready; + // sc_out out_receceive; + sc_in im_data; + + sc_out is_done; + std::unique_ptr image = std::make_unique(IN_SIZE); + std::vector process_image = std::vector( + OUT_SIZE, 0); // after isp process, the data of image + + SC_CTOR(TB_ISP) { + SC_CTHREAD(send_Data, clk.pos()); + reset_signal_is(reset, true); + + SC_CTHREAD(read_Data, clk.pos()); + } + + void send_Data(void) { + uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; + bool is_finish = false; + while (true) { + if (in_ready.read() && !is_finish) { + out_en.write(1); + + printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, + image[(pos_y + 0) * IN_WIDTH + pos_x]); + printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, + image[(pos_y + 1) * IN_WIDTH + pos_x]); + printf("x=%4d, y=%4d, data=0x%04x\n", pos_x, pos_y, + image[(pos_y + 2) * IN_WIDTH + pos_x]); + + out_data[0].write(image[(pos_y + 0) * IN_WIDTH + pos_x]); + out_data[1].write(image[(pos_y + 1) * IN_WIDTH + pos_x]); + out_data[2].write(image[(pos_y + 2) * IN_WIDTH + pos_x]); + + pos_x++; + if (pos_x >= IN_WIDTH) { + pos_x = 0; + pos_y++; + } + if (pos_y >= IN_HEIGHT - 2) { + pos_y = 0; + cnt_flame++; + } + if (cnt_flame >= FLAMES) { + is_finish = true; + } + } else { + out_en.write(0); + } + + wait(); + } + } + + void read_Data(void) { + is_done.write(0); + uint32_t pos_x = 0, pos_y = 0, cnt_flame = 0; + uint32_t last_data = 0, cnt = 0; + bool is_finish = false; + while (true) { + if (im_en.read() && !is_finish) { + out_ready.write(false); + + process_image[pos_y * OUT_WIDTH + pos_x] = im_data.read(); + 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.write(true); + // out_receceive.write(false); + } + + // when data didn't change some time, it end + if (last_data == im_data.read() && is_finish) { + cnt++; + if (cnt >= 100000L) { + is_done.write(1); + printf("x=%d, y=%d\n", pos_x, pos_y); + } + } else { + cnt = 0; + } + last_data = im_data.read(); + + 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; + } + + // Transform isp image + std::vector bmp_image(3 * OUT_SIZE); + for (int i = 0; i < OUT_SIZE; i++) { + bmp_image[3 * i + 0] = (process_image[i] & 0x00ff0000) >> 16; + bmp_image[3 * i + 1] = (process_image[i] & 0x0000ff00) >> 8; + bmp_image[3 * i + 2] = (process_image[i] & 0x000000ff) >> 0; + } + + // Write BMP image + std::ofstream bmp; + bmp.open(std::string(OUTPUT_DIR) + name); + if (!bmp.is_open()) { + std::cout << "Output File Open Failed!!!\n"; + return false; + } + ret = writeBMP(bmp, bmp_image, OUT_WIDTH, OUT_HEIGHT); + bmp.close(); + return ret; + } +}; + +bool picProcess(uint32_t *image, uint16_t number) { + uint8_t *data = new uint8_t[OUT_WIDTH * OUT_HEIGHT * 3]; // RGB24格式像素数据 + + // software algorthms analyze + uint32_t red_total = 0, green_total = 0, blue_total = 0; + uint8_t red_max = 0, green_max = 0, blue_max = 0; + for (int32_t y = 0; y < OUT_HEIGHT; ++y) { + for (int32_t x = 0; x < OUT_WIDTH; ++x) { + int32_t index = (y * OUT_WIDTH + x) * 3; + + uint8_t red = (image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16; + uint8_t green = (image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8; + uint8_t blue = (image[y * OUT_WIDTH + x] & 0x000000ff); + + // Adjust gamma line + // red = 255 * std::pow(red / 255.0, 1 / gamma_value); + // green = 255 * std::pow(green / 255.0, 1 / gamma_value); + // blue = 255 * std::pow(blue / 255.0, 1 / gamma_value); + + // Calculate white balance data + // red_max = std::max(red_max, red); + // green_max = std::max(green_max, green); + // blue_max = std::max(blue_max, blue); + // red_total += red; + // green_total += green; + // blue_total += blue; + + // Adjust vibrance + // uint8_t max = std::max({red, green, blue}); + // uint8_t min = std::min({red, green, blue}); + // double delta = (max - min) / 255.0; + // double value = (max + min) / 255.0; + // if (delta != 0) { + // double L = value / 2.0; + // // double S = (L <= 0.5) ? delta / value : delta / (2 - + // value); double S = delta / max; double alpha = 0.0; if + // (saturation_inc >= 0) { + // if ((saturation_inc + S) >= 1) + // alpha = S; + // else + // alpha = 1 - saturation_inc; + // alpha = 1 / alpha - 1; + // red = static_cast(red + (red - L * 255) * alpha); + // green = + // static_cast(green + (green - L * 255) * + // alpha); + // blue = static_cast(blue + (blue - L * 255) * + // alpha); + // } else { + // alpha = saturation_inc; + // red = static_cast(L * 255 + + // (red - L * 255) * (1 + alpha)); + // green = static_cast(L * 255 + + // (green - L * 255) * (1 + + // alpha)); + // blue = static_cast(L * 255 + + // (blue - L * 255) * (1 + + // alpha)); + // } + // } + + // Contrast enhancement + // red = static_cast(contrast * (red - 128) + 128); + // green = static_cast(contrast * (green - 128) + 128); + // blue = static_cast(contrast * (blue - 128) + 128); + + // save data + data[index + 0] = red; // R + data[index + 1] = green; // G + data[index + 2] = blue; // B + } + } + + // Adjust White Balance : Grey World Color Correction + // double K = static_cast(red_total + green_total + blue_total) / + // (3 * OUT_SIZE); + // white_gain.red = static_cast(K * OUT_SIZE) / red_total; + // white_gain.green = static_cast(K * OUT_SIZE) / green_total; + // white_gain.blue = static_cast(K * OUT_SIZE) / blue_total; + // printf("Gain: red = %f, green = %f, blue = %f", white_gain.red, + // white_gain.green, white_gain.blue); + // for (int32_t y = 0; y < OUT_HEIGHT; ++y) { + // for (int32_t x = 0; x < OUT_WIDTH; ++x) { + // int32_t index = (y * OUT_WIDTH + x) * 3; + + // data[index + 0] = + // static_cast(white_gain.red * data[index + 0]); + // data[index + 1] = + // static_cast(white_gain.green * data[index + 1]); + // data[index + 2] = + // static_cast(white_gain.blue * data[index + 2]); + // } + // } + + // save to bmp + std::cout << "Ready to save raw RGB image" << std::endl; + char file_name[64] = {0}; + snprintf(file_name, sizeof(file_name), "pic_%d.bmp", number); + write_bmp(file_name, data, OUT_WIDTH, OUT_HEIGHT); + delete[] data; + + return true; +} + +int sc_main(int argc, char *argv[]) { + std::cout << "Get into sc_main" << std::endl; + // Open image + std::ifstream in_image; + in_image.open(INPUT_IMG, std::ios::in | std::ios::binary); + if (!in_image.is_open()) { + std::cout << "Open image fail" << std::endl; + exit(0); + } else { + std::cout << "Ready to sim" << std::endl; + } + + // Read image + auto buf = std::make_unique(2 * IN_SIZE); + in_image.read((char *)buf.get(), IN_SIZE * 2); + in_image.close(); + // Reshape data + auto image = std::make_unique(IN_SIZE); + uint32_t i = 0; + for (int y = 0; y < IN_HEIGHT; y++) { + for (int x = 0; x < IN_WIDTH; x++) { + image[y * IN_WIDTH + x] = (uint16_t)buf[i] + ((uint16_t)buf[i + 1] << 8); + i += 2; + } + } + std::cout << "Finish Reading data" << std::endl; + + // 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"); + + // Set debug level, 0 is off, 9 is highest presently used + // May be overridden by commandArgs argument parsing + Verilated::debug(0); + + // Randomization reset policy + // May be overridden by commandArgs argument parsing + Verilated::randReset(2); + + // 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 + // This needs to be called before you create any model + Verilated::commandArgs(argc, argv); + + // General logfile + std::ios::sync_with_stdio(); + + // Define clocks + sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true}; + // Define interconnect + sc_signal reset; + + sc_signal in_en; + sc_signal in_ready; + // sc_signal in_receive; + sc_signal in_data[3]; + + sc_signal out_clk; + sc_signal out_en; + sc_signal out_ready; + sc_signal out_receive; + sc_signal out_data; + + sc_signal blender_enable; + sc_signal gain_red; + sc_signal gain_green; + sc_signal gain_blue; + + sc_signal gamma_enable; + sc_signal gamma_inverse; + sc_signal gamma_table[256]; + + sc_signal white_gain[3]; + sc_signal flame_rate; + sc_signal white_enable; + + sc_signal saturation_enable; + sc_signal saturation_increase; + + sc_signal flag_done; + + // Construct the Verilated model, from inside Visp.h + // Using unique_ptr is similar to "Visp* isp = new Visp" then deleting at + // end + const std::unique_ptr isp{new Visp{"isp"}}; + // Attach Visp's signals to this upper model + isp->clk(clk); + isp->reset(reset); + isp->in_en(in_en); + isp->in_ready(in_ready); + // isp->in_receive(in_receive); + isp->in_data[0](in_data[0]); + isp->in_data[1](in_data[1]); + isp->in_data[2](in_data[2]); + isp->out_en(out_en); + isp->out_ready(out_ready); + isp->out_receive(out_receive); + isp->out_data(out_data); + + isp->gain_red(gain_red); + isp->gain_green(gain_green); + isp->gain_blue(gain_blue); + isp->blender_enable(blender_enable); + + isp->gamma_enable(gamma_enable); + // isp->gamma_inverse(gamma_inverse); + + isp->white_enable(white_enable); + isp->flame_rate(flame_rate); + isp->white_gain[0](white_gain[0]); + isp->white_gain[1](white_gain[1]); + isp->white_gain[2](white_gain[2]); + + isp->saturation_enable(saturation_enable); + isp->saturation_inc(saturation_increase); + + blender_enable = true; // enable color correction + gain_red = static_cast(color_gain.red * std::pow(2, 8)); + gain_green = static_cast(color_gain.green * std::pow(2, 8)); + gain_blue = static_cast(color_gain.blue * std::pow(2, 8)); + + gamma_enable = true; + gamma_inverse = static_cast((1.0 / gamma_value) * std::pow(2, 8)); + for (int i = 0; i < 256; i++) { + // calculate gamma table + isp->gamma_table[i](gamma_table[i]); + gamma_table[i] = + static_cast(255 * pow(i / 255.0, 1.0 / gamma_value)); + } + + white_enable = true; + flame_rate = 0; + white_gain[0] = 255; + white_gain[1] = 255; + white_gain[2] = 255; + + saturation_enable = true; + saturation_increase = + (int32_t)((saturation_inc >= 0) ? (saturation_inc * std::pow(2, 8)) + : (saturation_inc * std::pow(2, 8))); + + // Construct testbench module + TB_ISP tb_isp("tb_isp"); + tb_isp.clk(clk); + tb_isp.reset(reset); + tb_isp.in_ready(out_ready); + tb_isp.in_receive(out_receive); + tb_isp.out_en(in_en); + tb_isp.out_ready(in_ready); + // tb_isp.out_receceive(in_receive); + tb_isp.out_data[0](in_data[0]); + tb_isp.out_data[1](in_data[1]); + tb_isp.out_data[2](in_data[2]); + tb_isp.im_en(out_en); + tb_isp.im_data(out_data); + tb_isp.is_done(flag_done); + tb_isp.image = std::move(image); + + // You must do one evaluation before enabling waves, in order to allow + // SystemC to interconnect everything for testing. + sc_start(SC_ZERO_TIME); + + // If verilator was invoked with --trace argument, + // and if at run time passed the +trace argument, turn on tracing + 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"; + tfp = new VerilatedVcdSc; + isp->trace(tfp, 99); // Trace 99 levels of hierarchy + Verilated::mkdir("logs"); + tfp->open("logs/vlt_dump.vcd"); + } + + // Simulate until $finish + while (!Verilated::gotFinish()) { + // Flush the wave files each cycle so we can immediately see the OUTPUT_DIR + // 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(10, SC_NS)) { + reset.write(1); // Assert reset + } else { + reset.write(0); // Deassert reset + } + + if (flag_done.read()) + break; + + // Simulate 1ns + sc_start(1, SC_NS); + } + + // Final model cleanup + isp->final(); + + // Close trace if opened + if (tfp) { + tfp->close(); + tfp = nullptr; + } + + // Return good completion status + return 0; +} diff --git a/src/sc_main.cpp.bak b/src/sc_main.cpp.bak index a88581b..fb692b4 100755 --- a/src/sc_main.cpp.bak +++ b/src/sc_main.cpp.bak @@ -1,294 +1,233 @@ -// For std::unique_ptr -#include +// For read and write +#include +#include +#include +#include +#include +#include // SystemC global header #include // Include common routines -#include // mkdir +#include +#include // mkdir +#include +#include #include #include // Include model header, generated from Verilating "isp.v" #include "Visp.h" -// Handle file -#include -#include - -// math -#include - +// Write Pictures #include "bmp.hpp" +#include "sysc/communication/sc_signal.h" +#include "sysc/kernel/sc_module.h" +// Image Parameters static const uint16_t IN_WIDTH = 1936; static const uint16_t IN_HEIGHT = 1088; static const uint32_t IN_SIZE = (IN_WIDTH * IN_HEIGHT); static const uint16_t OUT_WIDTH = 1920; static const uint16_t OUT_HEIGHT = 1080; static const uint32_t OUT_SIZE = (OUT_WIDTH * OUT_HEIGHT); -static const uint32_t FLAMES = 2; +static const uint32_t CNT_FLAME = 2; -// color gain for correcting color +// Input image path and Output directory path +const char *input = "./src/transform/test.bin"; +const char *output = "./logs/"; + +// Modules Configuration struct color_gain { double red; double green; double blue; -} color_gain{ 1.1, 0.7, 1.3 }, white_gain; +} color_gain{1.1, 0.7, 1.3}, white_gain; static const double gamma_value = 2.2; -static const double saturation_inc = 0.5; +static const double sat_inc = 0.5; static const double contrast = 1.2; -// static const double white_radio = 0.1; using namespace sc_core; using namespace sc_dt; -bool picProcess(uint32_t *image, uint16_t number); - SC_MODULE(TB_ISP) { sc_in_clk clk; - sc_in reset; + sc_in rst; - sc_in in_ready; - sc_out out_valid; - sc_out out_data[3]; + sc_in in_ready; // next module ready to receive data + sc_out out_valid; // next module data valid signal + sc_out out_data[3]; // next module receive data - sc_in im_clk; - sc_in im_en; - sc_out out_ready; - sc_in im_data; + sc_in in_valid; // this module receive data valid signal + sc_out out_ready; // this module ready to receive data + sc_in in_data; // this module receive data - sc_out is_done; - std::unique_ptr image = std::make_unique(IN_SIZE); - std::unique_ptr out = std::make_unique(OUT_SIZE); + bool is_done; // when receive all data + std::vector image; // the data of image + std::vector process_image = std::vector( + OUT_SIZE, 0); // after isp process, the data of image SC_CTOR(TB_ISP) { - SC_CTHREAD(send_Data, clk.pos()); - reset_signal_is(reset, true); + SC_CTHREAD(sendData, clk.pos()); // when clk posedge, exec sendData + reset_signal_is(rst, true); // set rst signal - SC_CTHREAD(read_Data, im_clk.pos()); + SC_CTHREAD(readData, clk.pos()); + reset_signal_is(rst, true); // set rst signal } - void send_Data(void) { + void sendData(void) { + // init var uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; - bool is_finish = false; + bool is_finish = false; // when send all data + // reset + out_valid = false; + for (auto &data : out_data) + data = 0; + while (true) { - if (in_ready.read() && !is_finish) { - out_valid.write(1); + 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]; - printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, - image[(pos_y + 0) * IN_WIDTH + pos_x]); - printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, - image[(pos_y + 1) * IN_WIDTH + pos_x]); - printf("x=%4d, y=%4d, data=0x%04x\n", pos_x, pos_y, - 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]); - out_data[0].write(image[(pos_y + 0) * IN_WIDTH + pos_x]); - out_data[1].write(image[(pos_y + 1) * IN_WIDTH + pos_x]); - out_data[2].write(image[(pos_y + 2) * IN_WIDTH + pos_x]); - - pos_x++; - if (pos_x >= IN_WIDTH) { + // calculate position and recognize when to finish + if (++pos_x >= IN_WIDTH) { pos_x = 0; - pos_y++; + if (++pos_y >= IN_HEIGHT - 2) { // demosaic window is 3x3 + pos_y = 0; + if (++cnt_flame >= CNT_FLAME) { + is_finish = true; + } + } } - if (pos_y >= IN_HEIGHT - 2) { - pos_y = 0; - cnt_flame++; - } - if (cnt_flame >= FLAMES) { - is_finish = true; - } - } - else { - out_valid.write(0); + } else { + out_valid = false; } + // wait for next clk wait(); } } - void read_Data(void) { - is_done.write(0); + 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) { - - // when not finish, read data if (!is_finish) { - out_ready.write(true); - if (im_en.read()) { - out[pos_y * OUT_WIDTH + pos_x] = im_data.read(); + out_ready = true; - pos_x++; - if (pos_x >= IN_WIDTH) { + // when data valid, write it down + if (in_valid) { + process_image[pos_y * OUT_WIDTH + pos_x] = in_data; + + // calculate position + if (++pos_x >= OUT_WIDTH) { pos_x = 0; - pos_y++; - } - if (pos_y >= IN_HEIGHT - 2) { - pos_y = 0; - cnt_flame++; + if (++pos_y >= OUT_HEIGHT) { + pos_y = 0; + if (++cnt_flame >= CNT_FLAME) { + is_finish = true; + } + + // Save image + saveData( + ("output_img_" + std::to_string(cnt_flame) + ".bmp").c_str()); + } } } - } - else { - out_ready.write(false); + } else { + out_ready = false; } - // when data didn't change some time, it end - if (last_data == im_data.read() && is_finish) { + // when no data send, give finish signal + if (is_finish && (last_data == in_data)) { cnt++; - if (cnt >= 100000L) { - is_done.write(1); - printf("x=%d, y=%d\n", pos_x, pos_y); + 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 { + } else { cnt = 0; } - last_data = im_data.read(); + last_data = in_data; + // wait for next clk wait(); } } + + bool saveData(const char *name) { + bool ret = true; + // Transform isp image + std::vector bmp_image(3 * OUT_SIZE); + for (int i = 0; i < OUT_SIZE; i++) { + bmp_image[i + 0] = (process_image[i] & 0x00ff0000) >> 16; + bmp_image[i + 1] = (process_image[i] & 0x0000ff00) >> 8; + bmp_image[i + 2] = (process_image[i] & 0x000000ff) >> 0; + } + + // Write BMP image + std::ofstream bmp; + bmp.open(std::string(output) + name); + if (!bmp.is_open()) { + std::cout << "Output File Open Failed!!!\n"; + return false; + } + ret = writeBMP(bmp, bmp_image, OUT_WIDTH, OUT_HEIGHT); + bmp.close(); + return ret; + } }; -bool picProcess(uint32_t *image, uint16_t number) { - uint8_t *data = - new uint8_t[OUT_WIDTH * OUT_HEIGHT * 3]; // RGB24格式像素数据 - - // software algorthms analyze - uint32_t red_total = 0, green_total = 0, blue_total = 0; - uint8_t red_max = 0, green_max = 0, blue_max = 0; - for (int32_t y = 0; y < OUT_HEIGHT; ++y) { - for (int32_t x = 0; x < OUT_WIDTH; ++x) { - int32_t index = (y * OUT_WIDTH + x) * 3; - - uint8_t red = (image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16; - uint8_t green = (image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8; - uint8_t blue = (image[y * OUT_WIDTH + x] & 0x000000ff); - - // Adjust gamma line - // red = 255 * std::pow(red / 255.0, 1 / gamma_value); - // green = 255 * std::pow(green / 255.0, 1 / gamma_value); - // blue = 255 * std::pow(blue / 255.0, 1 / gamma_value); - - // Calculate white balance data - // red_max = std::max(red_max, red); - // green_max = std::max(green_max, green); - // blue_max = std::max(blue_max, blue); - // red_total += red; - // green_total += green; - // blue_total += blue; - - // Adjust vibrance - // uint8_t max = std::max({red, green, blue}); - // uint8_t min = std::min({red, green, blue}); - // double delta = (max - min) / 255.0; - // double value = (max + min) / 255.0; - // if (delta != 0) { - // double L = value / 2.0; - // // double S = (L <= 0.5) ? delta / value : delta / (2 - - // value); double S = delta / max; double alpha = 0.0; if - // (saturation_inc >= 0) { - // if ((saturation_inc + S) >= 1) - // alpha = S; - // else - // alpha = 1 - saturation_inc; - // alpha = 1 / alpha - 1; - // red = static_cast(red + (red - L * 255) * alpha); - // green = - // static_cast(green + (green - L * 255) * - // alpha); - // blue = static_cast(blue + (blue - L * 255) * - // alpha); - // } else { - // alpha = saturation_inc; - // red = static_cast(L * 255 + - // (red - L * 255) * (1 + alpha)); - // green = static_cast(L * 255 + - // (green - L * 255) * (1 + - // alpha)); - // blue = static_cast(L * 255 + - // (blue - L * 255) * (1 + - // alpha)); - // } - // } - - // Contrast enhancement - // red = static_cast(contrast * (red - 128) + 128); - // green = static_cast(contrast * (green - 128) + 128); - // blue = static_cast(contrast * (blue - 128) + 128); - - - // save data - data[index + 0] = red; // R - data[index + 1] = green; // G - data[index + 2] = blue; // B - } - } - - // Adjust White Balance : Grey World Color Correction - // double K = static_cast(red_total + green_total + blue_total) / - // (3 * OUT_SIZE); - // white_gain.red = static_cast(K * OUT_SIZE) / red_total; - // white_gain.green = static_cast(K * OUT_SIZE) / green_total; - // white_gain.blue = static_cast(K * OUT_SIZE) / blue_total; - // printf("Gain: red = %f, green = %f, blue = %f", white_gain.red, - // white_gain.green, white_gain.blue); - // for (int32_t y = 0; y < OUT_HEIGHT; ++y) { - // for (int32_t x = 0; x < OUT_WIDTH; ++x) { - // int32_t index = (y * OUT_WIDTH + x) * 3; - - // data[index + 0] = - // static_cast(white_gain.red * data[index + 0]); - // data[index + 1] = - // static_cast(white_gain.green * data[index + 1]); - // data[index + 2] = - // static_cast(white_gain.blue * data[index + 2]); - // } - // } - - // save to bmp - std::cout << "Ready to save raw RGB image" << std::endl; - char file_name[64] = { 0 }; - snprintf(file_name, sizeof(file_name), "pic_%d.bmp", number); - write_bmp(file_name, data, OUT_WIDTH, OUT_HEIGHT); - delete[] data; - - return true; -} - int sc_main(int argc, char *argv[]) { - std::cout << "Get into sc_main" << std::endl; - // Open image - std::ifstream in_image; - in_image.open("./transform/test.bin", std::ios::in | std::ios::binary); - if (!in_image.is_open()) { - std::cout << "Open image fail" << std::endl; + std::printf("Enter into sc_main\n"); + + // Open Image + std::ifstream image; + image.open(input, std::ios::in | std::ios::binary); + // Check image whether is open + if (!image.is_open()) { + std::printf("Open Image Failed!!!\n"); exit(0); - } - else { - std::cout << "Ready to sim" << std::endl; + } else { + std::printf("Open Image Successfully!!!\n"); } - // Read image - auto buf = std::make_unique(2 * IN_SIZE); - in_image.read((char *)buf.get(), IN_SIZE * 2); - in_image.close(); - // Reshape data - auto image = std::make_unique(IN_SIZE); + // Read and Transform Image + std::vector in_image(IN_SIZE); + char *buf = new char[2 * IN_SIZE]; + image.read(buf, sizeof(buf)); uint32_t i = 0; for (int y = 0; y < IN_HEIGHT; y++) { - for (int x = 0; x < IN_WIDTH; x++) { - image[y * IN_WIDTH + x] = - (uint16_t)buf[i] + ((uint16_t)buf[i + 1] << 8); + for (int x = 0; x < IN_HEIGHT; x++) { + in_image[y * IN_HEIGHT + x] = + static_cast(i) + (static_cast(i + 1) << 8); i += 2; } } - std::cout << "Finish Reading data" << std::endl; + // Close and delete image + image.close(); + delete[] buf; + std::printf("Finish Reading Image\n"); // This is a more complicated example, please also see the simpler // examples/make_hello_c. @@ -316,110 +255,114 @@ int sc_main(int argc, char *argv[]) { std::ios::sync_with_stdio(); // Define clocks - sc_clock clk{ "clk", 10, SC_NS, 0.5, 3, SC_NS, true }; + sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true}; // Define interconnect - sc_signal reset; - + sc_signal rst; + // ISP Modules in ports sc_signal in_valid; sc_signal in_ready; sc_signal in_data[3]; - - sc_signal out_clk; + // ISP Modules out ports sc_signal out_valid; sc_signal out_ready; - sc_signal out_receive; sc_signal out_data; - + // ISP Modules Enable Ports sc_signal blender_enable; + sc_signal gamma_enable; + sc_signal white_enable; + sc_signal saturation_enable; + // ISP Modules Configurations Ports sc_signal gain_red; sc_signal gain_green; sc_signal gain_blue; - - sc_signal gamma_enable; - sc_signal gamma_inverse; - sc_signal gamma_table[256]; - - sc_signal white_gain[3]; sc_signal flame_rate; - sc_signal white_enable; - - sc_signal saturation_enable; - sc_signal saturation_increase; - - sc_signal flag_done; + sc_signal saturation_inc; + sc_signal gamma_table[256]; + sc_signal white_gain[3]; // Construct the Verilated model, from inside Visp.h - // Using unique_ptr is similar to "Visp* isp = new Visp" then deleting at the end - const std::unique_ptr isp{ new Visp{"isp"} }; - // Attach Visp's signals to this upper model - isp->clk(clk); - isp->reset(reset); - isp->in_valid(in_valid); - isp->in_ready(in_ready); - isp->in_data[0](in_data[0]); - isp->in_data[1](in_data[1]); - isp->in_data[2](in_data[2]); - isp->out_valid(out_valid); - isp->out_ready(out_ready); - isp->out_data(out_data); + Visp isp("Visp"); + // isp.clk(clk); + // isp.reset(rst); + // // Connect input signal + // isp.in_valid(in_valid); + // isp.in_ready(in_ready); + // for (int i = 0; i < 3; i++) + // isp.in_data[i](in_data[i]); + // // Connect output signal + // isp.out_valid(out_valid); + // isp.out_ready(out_ready); + // isp.out_data(out_data); + // // Connect ISP modules enable signal + // isp.blender_enable(blender_enable); + // // Connect ISP modules configuration signal + // isp.gain_red(gain_red); + // isp.gain_green(gain_green); + // isp.gain_blue(gain_blue); - isp->gain_red(gain_red); - isp->gain_green(gain_green); - isp->gain_blue(gain_blue); - isp->blender_enable(blender_enable); - - // isp->gamma_enable(gamma_enable); - // isp->gamma_inverse(gamma_inverse); - - // isp->white_enable(white_enable); - // isp->flame_rate(flame_rate); - // isp->white_gain[0](white_gain[0]); - // isp->white_gain[1](white_gain[1]); - // isp->white_gain[2](white_gain[2]); - - // isp->saturation_enable(saturation_enable); - // isp->saturation_inc(saturation_increase); - - // blender_enable = true; // enable color correction - // gain_red = static_cast(color_gain.red * std::pow(2, 8)); - // gain_green = static_cast(color_gain.green * std::pow(2, 8)); - // gain_blue = static_cast(color_gain.blue * std::pow(2, 8)); - - // gamma_enable = true; - // gamma_inverse = static_cast((1.0 / gamma_value) * std::pow(2, 8)); - // for (int i = 0; i < 256; i++) { - // // calculate gamma table - // isp->gamma_table[i](gamma_table[i]); - // gamma_table[i] = static_cast(255 * pow(i / 255.0, 1.0 / gamma_value)); - // } - - // white_enable = true; - // flame_rate = 0; - // white_gain[0] = 255; - // white_gain[1] = 255; - // white_gain[2] = 255; - - // saturation_enable = true; - // saturation_increase = - // (int32_t)((saturation_inc >= 0) ? (saturation_inc * std::pow(2, 8)) - // : (saturation_inc * std::pow(2, 8))); + // ISP Old Version + isp.clk(clk); + isp.reset(rst); + isp.in_en(in_valid); + isp.in_ready(in_ready); + for (int i = 0; i < 3; i++) + isp.in_data[i](in_data[i]); + sc_signal out_receive; + isp.out_receive(out_receive); + isp.out_en(out_valid); + isp.out_ready(out_ready); + isp.out_data(out_data); + isp.blender_enable(blender_enable); + isp.gamma_enable(gamma_enable); + isp.white_enable(white_enable); + isp.saturation_enable(saturation_enable); + isp.gain_red(gain_red); + isp.gain_green(gain_green); + isp.gain_blue(gain_blue); + isp.flame_rate(flame_rate); + isp.saturation_inc(saturation_inc); + for (int i = 0; i < 256; i++) + isp.gamma_table[i](gamma_table[i]); + for (int i = 0; i < 3; i++) + isp.white_gain[i](white_gain[i]); // Construct testbench module TB_ISP tb_isp("tb_isp"); + tb_isp.image = std::move(in_image); tb_isp.clk(clk); - tb_isp.reset(reset); + tb_isp.rst(rst); + // Connect input signal + tb_isp.in_valid(out_valid); tb_isp.in_ready(out_ready); + tb_isp.in_data(out_data); + // Connect output signal tb_isp.out_valid(in_valid); tb_isp.out_ready(in_ready); - // tb_isp.out_receceive(in_receive); - tb_isp.out_data[0](in_data[0]); - tb_isp.out_data[1](in_data[1]); - tb_isp.out_data[2](in_data[2]); - tb_isp.im_clk(out_clk); - tb_isp.im_en(out_valid); - tb_isp.im_data(out_data); - tb_isp.is_done(flag_done); - tb_isp.image = move(image); + for (int i = 0; i < 3; i++) + tb_isp.out_data[i](in_data[i]); + + // Set ISP modules parameters + // Color Blender + blender_enable = true; + gain_red = static_cast(color_gain.red * std::pow(2, 8)); + gain_green = static_cast(color_gain.green * std::pow(2, 8)); + gain_blue = static_cast(color_gain.blue * std::pow(2, 8)); + // Gamma table + gamma_enable = true; + for (int i = 0; i < 256; i++) { + gamma_table[i] = + static_cast(255 * pow(i / 255.0, 1.0 / gamma_value)); + } + // White Correction + white_enable = true; + flame_rate = 0; + white_gain[0] = 255; + white_gain[1] = 255; + white_gain[2] = 255; + // Saturation Correction + saturation_enable = true; + saturation_inc = (int32_t)((sat_inc >= 0) ? (sat_inc * std::pow(2, 8)) + : (sat_inc * std::pow(2, 8))); // You must do one evaluation before enabling waves, in order to allow // SystemC to interconnect everything for testing. @@ -432,33 +375,35 @@ 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; - isp->trace(tfp, 99); // Trace 99 levels of hierarchy + isp.trace(tfp, 99); // Trace 99 levels of hierarchy Verilated::mkdir("logs"); tfp->open("logs/vlt_dump.vcd"); } // Simulate until $finish + std::cout << "Ready to simulate!\n"; 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(); + if (tfp) + tfp->flush(); // Apply inputs if (sc_time_stamp() < sc_time(10, SC_NS)) { - reset.write(1); // Assert reset - } - else { - reset.write(0); // Deassert reset + rst.write(1); // Assert reset + } else { + rst.write(0); // Deassert reset } - if (flag_done.read()) break; + if (tb_isp.is_done) + break; // Simulate 1ns sc_start(1, SC_NS); } // Final model cleanup - isp->final(); + isp.final(); // Close trace if opened if (tfp) { diff --git a/src/tb_isp.cpp b/src/tb_isp.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/tb_isp.hpp b/src/tb_isp.hpp deleted file mode 100644 index 9b43428..0000000 --- a/src/tb_isp.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __TB_ISP_HPP__ -#define __TB_ISP_HPP__ - -#include "sysc/communication/sc_signal_ports.h" -#include - -namespace testbench { -using namespace sc_core; -using namespace sc_dt; - -SC_MODULE(TB_ISP) { - sc_in_clk clk; - sc_in rst; - - sc_in in_ready; - sc_out out_valid; - sc_out> out_data[3]; - - sc_in in_data; -}; - -} // namespace testbench - -#endif diff --git a/src/transform/bmp.cpp b/src/transform/bmp.cpp deleted file mode 100755 index a82c004..0000000 --- a/src/transform/bmp.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "bmp.hpp" - -#include -#include - -// 将RGB24格式像素数据封装为BMP图像 -bool write_bmp(const char* filename, uint8_t* data, int32_t width, - int32_t height) { - BMPFileHeader file_header = {0}; - BMPInfoHeader info_header = {0}; - std::ofstream ofs(filename, std::ios::binary); - if (!ofs) { - std::cerr << "Failed to create file: " << filename << std::endl; - return false; - } - // BMP文件头 - file_header.type = 0x4D42; // BM - file_header.size = - sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + width * height * 3; - file_header.offset = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader); - ofs.write(reinterpret_cast(&file_header), sizeof(file_header)); - - // BMP位图信息头 - info_header.size = sizeof(BMPInfoHeader); - info_header.width = width; - info_header.height = height; - info_header.planes = 1; - info_header.bit_count = 24; - info_header.size_image = width * height * 3; - ofs.write(reinterpret_cast(&info_header), sizeof(info_header)); - - // 像素数据 - int32_t row_size = (((width + 1) * 3) / 4) * 4; // 行字节数,必须为4的倍数 - uint8_t* row_data = new uint8_t[row_size]; - for (int32_t y = height - 1; y >= 0; --y) { // BMP图像的行是从下往上存储的 - for (int32_t x = 0; x < width; ++x) { - row_data[x * 3 + 2] = data[(y * width + x) * 3 + 0]; // B - row_data[x * 3 + 1] = data[(y * width + x) * 3 + 1]; // G - row_data[x * 3 + 0] = data[(y * width + x) * 3 + 2]; // R - } - ofs.write(reinterpret_cast(row_data), row_size); - } - delete[] row_data; - ofs.close(); - return true; -} \ No newline at end of file diff --git a/src/transform/bmp.hpp b/src/transform/bmp.hpp deleted file mode 100755 index 8afcffc..0000000 --- a/src/transform/bmp.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __BMP_H__ -#define __BMP_H__ - -#include -#pragma pack(push, 1) // 1字节对齐 - -// BMP文件头结构体 -struct BMPFileHeader { - uint16_t type; // 文件类型,必须为"BM" - uint32_t size; // 文件大小,单位为字节 - uint16_t reserved1; // 保留字段,必须为0 - uint16_t reserved2; // 保留字段,必须为0 - uint32_t offset; // 像素数据起始位置,单位为字节 -}; - -// BMP位图信息头结构体 -struct BMPInfoHeader { - uint32_t size; // 信息头大小,必须为40 - int32_t width; // 图像宽度,单位为像素 - int32_t height; // 图像高度,单位为像素 - uint16_t planes; // 颜色平面数,必须为1 - uint16_t bit_count; // 每个像素的位数,必须为24 - uint32_t compression; // 压缩方式,必须为0 - uint32_t size_image; // 像素数据大小,单位为字节 - int32_t x_pels_per_meter; // X方向像素数/米 - int32_t y_pels_per_meter; // Y方向像素数/米 - uint32_t clr_used; // 使用的颜色数,必须为0 - uint32_t clr_important; // 重要的颜色数,必须为0 -}; - -#pragma pack(pop) - -bool write_bmp(const char* filename, uint8_t* data, int32_t width, int32_t height); - -#endif \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index c2dddab..93b3252 100644 --- a/xmake.lua +++ b/xmake.lua @@ -7,9 +7,16 @@ local INCLUDE_DIRS = path.splitenv( target("TB_ISP") set_toolchains("gcc") + set_languages("c++17") --- C/C++ Codes add_files( "src/**.cpp" ) --- Include directories - add_includedirs("src", ".", INCLUDE_DIRS) \ No newline at end of file + add_includedirs( + ".", + "src", + "obj_dir", + "src/img_process", + INCLUDE_DIRS + ) \ No newline at end of file