diff --git a/.envrc b/.envrc index 5bf8fc1..cffc922 100644 --- a/.envrc +++ b/.envrc @@ -1,3 +1 @@ -source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0=" - -use devenv \ No newline at end of file +use flake . --impure diff --git a/.gitignore b/.gitignore index 0028e69..c1ea4a6 100755 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,13 @@ *.png !im.tif *.bmp -*.out# Devenv +*.out + +# xmake +.xmake* +build + +# Devenv .devenv* devenv.local.nix diff --git a/Color/ColorBlender.sv b/Color/ColorBlender.sv deleted file mode 100644 index 9e079d9..0000000 --- a/Color/ColorBlender.sv +++ /dev/null @@ -1,110 +0,0 @@ -`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 in_en, - input wire [15:0] in_data[3], // 0:R 1:G 2:B - output wire out_ready, - 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, - input wire [15:0] gain_green, - 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; - - reg [2:0] state, nextState; - reg [32 - 1:0] data_cal[3]; // 用于保存运算结果,防止溢出 - - always @(posedge clk) begin - 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 - - 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 - -endmodule diff --git a/Color/GammaCorrection.sv b/Color/GammaCorrection.sv deleted file mode 100644 index 8dbe6c2..0000000 --- a/Color/GammaCorrection.sv +++ /dev/null @@ -1,89 +0,0 @@ -`timescale 1ns / 1ps - -module GammaCorrection #( - parameter reg [4:0] COLOR_DEPTH = 8 -) ( - input wire clk, - input wire reset, - - input wire in_en, - input wire [COLOR_DEPTH - 1 : 0] in_data[3], - output wire out_ready, - output wire out_receive, - - output reg out_en, - output reg [COLOR_DEPTH - 1 : 0] out_data[3], - input wire in_ready, - input wire in_receive, - - input wire enable, - input wire [9:0] gamma_inverse -); - reg [2:0] state, nextState; - localparam reg [2:0] READ_DATA = 0; - localparam reg [2:0] CALC_DATA = 1; - localparam reg [2:0] SEND_DATA = 2; - - reg [15:0] data_cal[3]; - - always @(posedge clk or posedge reset) begin - if (reset) state <= READ_DATA; - else state <= nextState; - end - - always @(*) begin - case (state) - READ_DATA: nextState = in_en ? CALC_DATA : READ_DATA; - CALC_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) ? 1 : 0; - assign out_receive = (in_en && state == READ_DATA) ? 1 : 0; - - always @(posedge clk or posedge reset) begin - if (reset) begin - out_en <= 0; - out_data[0] <= 0; - out_data[1] <= 0; - out_data[2] <= 0; - - data_cal[0] <= 0; - data_cal[1] <= 0; - data_cal[2] <= 0; - end else begin - case (state) - READ_DATA: begin - if (in_en) begin - data_cal[0] <= {8'b0, in_data[0]}; - data_cal[1] <= {8'b0, in_data[1]}; - data_cal[2] <= {8'b0, in_data[2]}; - end - end - - CALC_DATA: begin - if (enable) begin - data_cal[0] <= data_cal[0] ** gamma_inverse; - data_cal[1] <= data_cal[1] ** gamma_inverse; - data_cal[2] <= data_cal[2] ** gamma_inverse; - end - end - - SEND_DATA: begin - if (in_ready) begin - out_en <= 1; - out_data[0] <= data_cal[0][COLOR_DEPTH-1 : 0]; - out_data[1] <= data_cal[1][COLOR_DEPTH-1 : 0]; - out_data[2] <= data_cal[2][COLOR_DEPTH-1 : 0]; - end else out_en <= 0; - end - - default: ; - endcase - end - end - - -endmodule diff --git a/Crop/Crop.sv b/Crop/Crop.sv deleted file mode 100644 index 832ac92..0000000 --- a/Crop/Crop.sv +++ /dev/null @@ -1,103 +0,0 @@ -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/Demosaic/Demosaic2.sv b/Demosaic/Demosaic2.sv deleted file mode 100644 index eae5640..0000000 --- a/Demosaic/Demosaic2.sv +++ /dev/null @@ -1,186 +0,0 @@ -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/Demosaic/demosaic.v b/Demosaic/demosaic.v deleted file mode 100644 index dd98bb6..0000000 --- a/Demosaic/demosaic.v +++ /dev/null @@ -1,259 +0,0 @@ -module demosaic #( - parameter IM_WIDTH = 512, - parameter IM_HEIGHT = 256 -)( - input clk, - input reset, - input in_en, - input [7:0] data_in, - output reg wr_r, - output reg [13:0] addr_r, - output reg [7:0] wdata_r, - input [7:0] rdata_r, - output reg wr_g, - output reg [13:0] addr_g, - output reg [7:0] wdata_g, - input [7:0] rdata_g, - output reg wr_b, - output reg [13:0] addr_b, - output reg [7:0] wdata_b, - input [7:0] rdata_b, - output reg done -); - -parameter IM_SIZE = IM_HEIGHT * IM_WIDTH; - -// Register -reg [1:0] bilinearCase; -reg [2:0] state, nextState; -reg [3:0] counter9; -reg [6:0] round; -reg [11:0] caseCounter; -reg [7:0] data [8:0]; -reg [7:0] red, blue, green; -reg [14:0] counter, biCounter; // bicounter store the center address - -// State parameter -localparam READDATA = 0; // Read data, then wirte to wdata -localparam COLOR = 1; // Choose the case of color -localparam STORE9 = 2; // Store 9 element to register data -localparam BILINEAR = 3; // Bilinear Interpolation -localparam WRITEDATA = 4; // Write data to memory -localparam FINISH = 5; // Done - -// State control -always @(posedge clk or posedge reset) begin - if(reset) - state <= READDATA; - else - state <= nextState; -end - -//next state logic -always @(*) begin - case (state) - READDATA: nextState = (counter == IM_SIZE)? COLOR : READDATA; - COLOR: nextState = STORE9; - STORE9: nextState = (counter9 == 4'd9)? BILINEAR : STORE9; - BILINEAR: nextState = WRITEDATA; - WRITEDATA: nextState = (biCounter == ( IM_SIZE - IM_WIDTH + 1 ))? FINISH : COLOR; - FINISH: nextState = FINISH; - default: nextState = READDATA; - endcase -end - -always @(posedge clk or posedge reset) begin - if (reset) begin - done <= 1'd0; - wr_r <= 1'd0; - wr_g <= 1'd0; - wr_b <= 1'd0; - bilinearCase <= 2'd0; - counter9 <= 4'd0; - caseCounter <= 7'd0; - round <= 7'd0; - red <= 9'd0; - blue <= 9'd0; - green <= 9'd0; - addr_r <= 14'd0; - addr_g <= 14'd0; - addr_b <= 14'd0; - biCounter <= 15'd129; - counter <= 15'd0; - end - else begin - case (state) - READDATA: begin - if(in_en) begin - wr_r <= 1'd1; - wr_g <= 1'd1; - wr_b <= 1'd1; - addr_r <= counter; - addr_g <= counter; - addr_b <= counter; - wdata_r <= data_in; - wdata_g <= data_in; - wdata_b <= data_in; - counter <= counter + 1; - end - end - - COLOR: begin - wr_r <= 1'd0; - wr_g <= 1'd0; - wr_b <= 1'd0; - - if(!(round & 1)) begin // Even round, 0,2,4,6,8,... - if(!(caseCounter & 1)) // Even case, 0,2,4,6,8,... - bilinearCase <= 2'd0; - else // Odd case, 1,3,5,7,9,... - bilinearCase <= 2'd1; - end - else begin // Odd round, 1,3,5,7,9,... - if(!(caseCounter & 1)) // Even case, 0,2,4,6,8,... - bilinearCase <= 2'd2; - else // Odd case, 1,3,5,7,9,... - bilinearCase <= 2'd3; - end - caseCounter <= caseCounter + 7'd1; - end - - STORE9: begin - wr_r <= 1'd0; - wr_g <= 1'd0; - wr_b <= 1'd0; - - /* - * I use R,G,B memory to store pattern data. when in case 0(the middle color is green), I will update the missing blue and red data to memory. - * In next turn is case 1(the middle color is blue). It will use previous data, but the blue and red data are changed in previous turn. So the - * previous green data is the origin data. - */ - if(counter9 > 4'd0) begin - case (bilinearCase) - 0: begin - case (counter9) - 2: data[counter9 - 1] <= rdata_r; - 4: data[counter9 - 1] <= rdata_b; - default: data[counter9 - 1] <= rdata_g; - endcase - end - 1: begin - case (counter9) - 1,3: data[counter9 - 1] <= rdata_r; - 2,4: data[counter9 - 1] <= rdata_g; - default: data[counter9 - 1] <= rdata_b; - endcase - end - 2: begin - case (counter9) - 1,3: data[counter9 - 1] <= rdata_b; - 2,4: data[counter9 - 1] <= rdata_g; - default: data[counter9 - 1] <= rdata_r; - endcase - end - 3: begin - case (counter9) - 2: data[counter9 - 1] <= rdata_b; - 4: data[counter9 - 1] <= rdata_r; - default: data[counter9 - 1] <= rdata_g; - endcase - end - endcase - end - counter9 <= counter9 + 4'd1; - - case (counter9) // For y axis (row) - 0,1,2: begin - addr_g[13:7] <= biCounter[13:7] - 7'd1; - addr_r[13:7] <= biCounter[13:7] - 7'd1; - addr_b[13:7] <= biCounter[13:7] - 7'd1; - end - 3,4,5: begin - addr_g[13:7] <= biCounter[13:7]; - addr_r[13:7] <= biCounter[13:7]; - addr_b[13:7] <= biCounter[13:7]; - end - 6,7,8: begin - addr_g[13:7] <= biCounter[13:7] + 7'd1; - addr_r[13:7] <= biCounter[13:7] + 7'd1; - addr_b[13:7] <= biCounter[13:7] + 7'd1; - end - endcase - - case (counter9) // For x axis (col) - 0,3,6: begin - addr_g[6:0] <= biCounter[6:0] - 7'd1; - addr_r[6:0] <= biCounter[6:0] - 7'd1; - addr_b[6:0] <= biCounter[6:0] - 7'd1; - end - 1,4,7: begin - addr_g[6:0] <= biCounter[6:0]; - addr_r[6:0] <= biCounter[6:0]; - addr_b[6:0] <= biCounter[6:0]; - end - 2,5,8: begin - addr_g[6:0] <= biCounter[6:0] + 7'd1; - addr_r[6:0] <= biCounter[6:0] + 7'd1; - addr_b[6:0] <= biCounter[6:0] + 7'd1; - end - endcase - end - - BILINEAR: begin - // data case 0 case 1 case 2 case 3 - // 0 1 2 G R G R G R B G B G B G - // 3 4 5 B G B G B G G R G R G R - // 6 7 8 G R G R G R B G B G B G - case (bilinearCase) - 0: begin // Missing B, R on G - red <= (data[1] + data[7]) / 2; - blue <= (data[3] + data[5]) / 2; - green <= data[4]; - end - - 1: begin // Missing G, R on B - green <= (data[1] + data[3] + data[5] + data[7]) / 4; - red <= (data[0] + data[2] + data[6] + data[8]) / 4; - blue <= data[4]; - end - - 2: begin // Missing G, B on R - green <= (data[1] + data[3] + data[5] + data[7]) / 4; - blue <= (data[0] + data[2] + data[6] + data[8]) / 4; - red <= data[4]; - end - - 3: begin // Missing B, R on G - blue <= (data[1] + data[7]) / 2; - red <= (data[3] + data[5]) / 2; - green <= data[4]; - end - endcase - end - - WRITEDATA: begin - wr_r <= 1'd1; - wr_g <= 1'd1; - wr_b <= 1'd1; - addr_r <= biCounter; - addr_g <= biCounter; - addr_b <= biCounter; - wdata_r <= red; - wdata_g <= green; - wdata_b <= blue; - if(caseCounter == ( IM_WIDTH - 2 )) begin // Finish one row, then initialize the caseCounter - caseCounter <= 7'd0; - round <= round + 7'd1; - biCounter <= biCounter + 15'd3; // Skip the edge - end - else - biCounter <= biCounter + 15'd1; - end - - FINISH: begin - done <= 1'd1; - end - endcase - end -end -endmodule \ No newline at end of file diff --git a/FPGA.nix b/FPGA.nix new file mode 100644 index 0000000..bd730d8 --- /dev/null +++ b/FPGA.nix @@ -0,0 +1,33 @@ +{ config, pkgs, ... }: { + # Add packages to the dev environment + packages = with pkgs; [ + # FPGA + verilator + systemc + verible + svls + + # C/C++ + gnumake + xmake + gcc + clang-tools + bear + ]; + + # Enable languages support + # languages.cplusplus.enable = true; + + # When enter shell, exec ... + enterShell = '' + export SYSTEMC_INCLUDE="${pkgs.systemc}/include" + export SYSTEMC_LIBDIR="${pkgs.systemc}/lib" + export VERILATOR_INCLUDE="${pkgs.verilator}/share/verilator/include" + echo + verilator --version + echo + gcc --version + ''; + +} + diff --git a/sim/Makefile b/Makefile old mode 100644 new mode 100755 similarity index 91% rename from sim/Makefile rename to Makefile index f04bc99..4f4622d --- a/sim/Makefile +++ b/Makefile @@ -32,9 +32,6 @@ VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage endif VERILATOR_FLAGS = -# Specify top module -TOP_MODULE = isp -VERILATOR_FLAGS += --top-module $(TOP_MODULE) # Generate SystemC in executable form VERILATOR_FLAGS += -sc --exe # Generate makefile dependencies (not shown as complicates the Makefile) @@ -55,10 +52,19 @@ VERILATOR_FLAGS += --threads 14 #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 -SOURCES := $(wildcard ../isp.sv *.cpp ../Demosaic/Demosaic2.sv ../Crop/*.sv ../Color/*.sv) -EXCLUDES := $(wildcard ../Color/WhiteBalance.sv ../Color/GammaCorrection.sv) +# 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) diff --git a/Scaler/scaler.v b/Scaler/scaler.v deleted file mode 100644 index 09ad584..0000000 --- a/Scaler/scaler.v +++ /dev/null @@ -1,760 +0,0 @@ -/*----------------------------------------------------------------------------- - - Video Stream Scaler - - Author: David Kronstein - - - -Copyright 2011, David Kronstein, and individual contributors as indicated -by the @authors tag. - -This is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation; either version 2.1 of -the License, or (at your option) any later version. - -This software is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this software; if not, write to the Free -Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -02110-1301 USA, or see the FSF site: http://www.fsf.org. - - -------------------------------------------------------------------------------- - -Scales streaming video up or down in resolution. Bilinear and nearest neighbor -modes are supported. - -Run-time adjustment of input and output resolution, scaling factors, and scale -type. - -------------------------------------------------------------------------------- - -Revisions - -V1.0.0 Feb 21 2011 Initial Release David Kronstein -Known bugs: -Very slight numerical errors (+0/-2 LSb) in output data due to coefficient arithmetic. -Impossible to notice without adjustment in video levels. Attempted to fix by setting -coeff11 to 1.0 - other coefficients, but this caused timing issues. - -*/ -`default_nettype none - -module streamScaler #( -//---------------------------Parameters---------------------------------------- -parameter DATA_WIDTH = 8, //Width of input/output data -parameter CHANNELS = 1, //Number of channels of DATA_WIDTH, for color images -parameter DISCARD_CNT_WIDTH = 8, //Width of inputDiscardCnt -parameter INPUT_X_RES_WIDTH = 11, //Widths of input/output resolution control signals -parameter INPUT_Y_RES_WIDTH = 11, -parameter OUTPUT_X_RES_WIDTH = 11, -parameter OUTPUT_Y_RES_WIDTH = 11, -parameter FRACTION_BITS = 8, //Number of bits for fractional component of coefficients. - -parameter SCALE_INT_BITS = 4, //Width of integer component of scaling factor. The maximum input data width to - //multipliers created will be SCALE_INT_BITS + SCALE_FRAC_BITS. Typically these - //values will sum to 18 to match multipliers available in FPGAs. -parameter SCALE_FRAC_BITS = 14, //Width of fractional component of scaling factor -parameter BUFFER_SIZE = 4, //Depth of RFIFO -//---------------------Non-user-definable parameters---------------------------- -parameter COEFF_WIDTH = FRACTION_BITS + 1, -parameter SCALE_BITS = SCALE_INT_BITS + SCALE_FRAC_BITS, -parameter BUFFER_SIZE_WIDTH = ((BUFFER_SIZE+1) <= 2) ? 1 : //wide enough to hold value BUFFER_SIZE + 1 - ((BUFFER_SIZE+1) <= 4) ? 2 : - ((BUFFER_SIZE+1) <= 8) ? 3 : - ((BUFFER_SIZE+1) <= 16) ? 4 : - ((BUFFER_SIZE+1) <= 32) ? 5 : - ((BUFFER_SIZE+1) <= 64) ? 6 : 7 -)( -//---------------------------Module IO----------------------------------------- -//Clock and reset -input wire clk, -input wire rst, - -//User interface -//Input -input wire [DATA_WIDTH*CHANNELS-1:0]dIn, -input wire dInValid, -output wire nextDin, -input wire start, - -//Output -output reg [DATA_WIDTH*CHANNELS-1:0] - dOut, -output reg dOutValid, //latency of 4 clock cycles after nextDout is asserted -input wire nextDout, - -//Control -input wire [DISCARD_CNT_WIDTH-1:0] inputDiscardCnt, //Number of input pixels to discard before processing data. Used for clipping -input wire [INPUT_X_RES_WIDTH-1:0] inputXRes, //Resolution of input data minus 1 -input wire [INPUT_Y_RES_WIDTH-1:0] inputYRes, -input wire [OUTPUT_X_RES_WIDTH-1:0] outputXRes, //Resolution of output data minus 1 -input wire [OUTPUT_Y_RES_WIDTH-1:0] outputYRes, -input wire [SCALE_BITS-1:0] xScale, //Scaling factors. Input resolution scaled up by 1/xScale. Format Q SCALE_INT_BITS.SCALE_FRAC_BITS -input wire [SCALE_BITS-1:0] yScale, //Scaling factors. Input resolution scaled up by 1/yScale. Format Q SCALE_INT_BITS.SCALE_FRAC_BITS - -input wire [OUTPUT_X_RES_WIDTH-1+SCALE_FRAC_BITS:0] - leftOffset, //Integer/fraction of input pixel to offset output data horizontally right. Format Q OUTPUT_X_RES_WIDTH.SCALE_FRAC_BITS -input wire [SCALE_FRAC_BITS-1:0] topFracOffset, //Fraction of input pixel to offset data vertically down. Format Q0.SCALE_FRAC_BITS -input wire nearestNeighbor //Use nearest neighbor resize instead of bilinear -); -//-----------------------Internal signals and registers------------------------ -reg advanceRead1; -reg advanceRead2; - -wire [DATA_WIDTH*CHANNELS-1:0] readData00; -wire [DATA_WIDTH*CHANNELS-1:0] readData01; -wire [DATA_WIDTH*CHANNELS-1:0] readData10; -wire [DATA_WIDTH*CHANNELS-1:0] readData11; -reg [DATA_WIDTH*CHANNELS-1:0] readData00Reg; -reg [DATA_WIDTH*CHANNELS-1:0] readData01Reg; -reg [DATA_WIDTH*CHANNELS-1:0] readData10Reg; -reg [DATA_WIDTH*CHANNELS-1:0] readData11Reg; - -wire [INPUT_X_RES_WIDTH-1:0] readAddress; - -reg readyForRead; //Indicates two full lines have been put into the buffer -reg [OUTPUT_Y_RES_WIDTH-1:0] outputLine; //which output video line we're on -reg [OUTPUT_X_RES_WIDTH-1:0] outputColumn; //which output video column we're on -reg [INPUT_X_RES_WIDTH-1+SCALE_FRAC_BITS:0] - xScaleAmount; //Fractional and integer components of input pixel select (multiply result) -reg [INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:0] - yScaleAmount; //Fractional and integer components of input pixel select (multiply result) -reg [INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:0] - yScaleAmountNext; //Fractional and integer components of input pixel select (multiply result) -wire [BUFFER_SIZE_WIDTH-1:0] fillCount; //Numbers used rams in the ram fifo -reg lineSwitchOutputDisable; //On the end of an output line, disable the output for one cycle to let the RAM data become valid -reg dOutValidInt; - -reg [COEFF_WIDTH-1:0] xBlend; -wire [COEFF_WIDTH-1:0] yBlend = {1'b0, yScaleAmount[SCALE_FRAC_BITS-1:SCALE_FRAC_BITS-FRACTION_BITS]}; - -wire [INPUT_X_RES_WIDTH-1:0] xPixLow = xScaleAmount[INPUT_X_RES_WIDTH-1+SCALE_FRAC_BITS:SCALE_FRAC_BITS]; -wire [INPUT_Y_RES_WIDTH-1:0] yPixLow = yScaleAmount[INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:SCALE_FRAC_BITS]; -wire [INPUT_Y_RES_WIDTH-1:0] yPixLowNext = yScaleAmountNext[INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:SCALE_FRAC_BITS]; - -wire allDataWritten; //Indicates that all data from input has been read in -reg readState; - -//States for read state machine -parameter RS_START = 0; -parameter RS_READ_LINE = 1; - -//Read state machine -//Controls the RFIFO(ram FIFO) readout and generates output data valid signals -always @ (posedge clk or posedge rst or posedge start) -begin - if(rst | start) - begin - outputLine <= 0; - outputColumn <= 0; - xScaleAmount <= 0; - yScaleAmount <= 0; - readState <= RS_START; - dOutValidInt <= 0; - lineSwitchOutputDisable <= 0; - advanceRead1 <= 0; - advanceRead2 <= 0; - yScaleAmountNext <= 0; - end - else - begin - case (readState) - - RS_START: - begin - xScaleAmount <= leftOffset; - yScaleAmount <= {{INPUT_Y_RES_WIDTH{1'b0}}, topFracOffset}; - if(readyForRead) - begin - readState <= RS_READ_LINE; - dOutValidInt <= 1; - end - end - - RS_READ_LINE: - begin - - //outputLine goes through all output lines, and the logic determines which input lines to read into the RRB and which ones to discard. - if(nextDout && dOutValidInt) - begin - if(outputColumn == outputXRes) - begin //On the last input pixel of the line - if(yPixLowNext == (yPixLow + 1)) //If the next input line is only one greater, advance the RRB by one only - begin - advanceRead1 <= 1; - if(fillCount < 3) //If the RRB doesn't have enough data, stop reading it out - dOutValidInt <= 0; - end - else if(yPixLowNext > (yPixLow + 1)) //If the next input line is two or more greater, advance the read by two - begin - advanceRead2 <= 1; - if(fillCount < 4) //If the RRB doesn't have enough data, stop reading it out - dOutValidInt <= 0; - end - - outputColumn <= 0; - xScaleAmount <= leftOffset; - outputLine <= outputLine + 1; - yScaleAmount <= yScaleAmountNext; - lineSwitchOutputDisable <= 1; - end - else - begin - //Advance the output pixel selection values except when waiting for the ram data to become valid - if(lineSwitchOutputDisable == 0) - begin - outputColumn <= outputColumn + 1; - xScaleAmount <= (outputColumn + 1) * xScale + leftOffset; - end - advanceRead1 <= 0; - advanceRead2 <= 0; - lineSwitchOutputDisable <= 0; - end - end - else //else from if(nextDout && dOutValidInt) - begin - advanceRead1 <= 0; - advanceRead2 <= 0; - lineSwitchOutputDisable <= 0; - end - - //Once the RRB has enough data, let data be read from it. If all input data has been written, always allow read - if(fillCount >= 2 && dOutValidInt == 0 || allDataWritten) - begin - if((!advanceRead1 && !advanceRead2)) - begin - dOutValidInt <= 1; - lineSwitchOutputDisable <= 0; - end - end - end//state RS_READ_LINE: - endcase - - //yScaleAmountNext is used to determine which input lines are valid. - yScaleAmountNext <= (outputLine + 1) * yScale + {{OUTPUT_Y_RES_WIDTH{1'b0}}, topFracOffset}; - end -end - -assign readAddress = xPixLow; - -//Generate dOutValid signal, delayed to account for delays in data path -reg dOutValid_1; -reg dOutValid_2; -reg dOutValid_3; - -always @(posedge clk or posedge rst) -begin - if(rst) - begin - dOutValid_1 <= 0; - dOutValid_2 <= 0; - dOutValid_3 <= 0; - dOutValid <= 0; - end - else - begin - dOutValid_1 <= nextDout && dOutValidInt && !lineSwitchOutputDisable; - dOutValid_2 <= dOutValid_1; - dOutValid_3 <= dOutValid_2; - dOutValid <= dOutValid_3; - end -end - -//-----------------------Output data generation----------------------------- -//Scale amount values are used to generate coefficients for the four pixels coming out of the RRB to be multiplied with. - -//Coefficients for each of the four pixels -//Format Q1.FRACTION_BITS -// yx -reg [COEFF_WIDTH-1:0] coeff00; //Top left -reg [COEFF_WIDTH-1:0] coeff01; //Top right -reg [COEFF_WIDTH-1:0] coeff10; //Bottom left -reg [COEFF_WIDTH-1:0] coeff11; //Bottom right - -//Coefficient value of one, format Q1.COEFF_WIDTH-1 -wire [COEFF_WIDTH-1:0] coeffOne = {1'b1, {(COEFF_WIDTH-1){1'b0}}}; //One in MSb, zeros elsewhere -//Coefficient value of one half, format Q1.COEFF_WIDTH-1 -wire [COEFF_WIDTH-1:0] coeffHalf = {2'b01, {(COEFF_WIDTH-2){1'b0}}}; - -//Compute bilinear interpolation coefficinets. Done here because these pre-registerd values are used twice. -//Adding coeffHalf to get the nearest value. -wire [COEFF_WIDTH-1:0] preCoeff00 = (((coeffOne - xBlend) * (coeffOne - yBlend) + (coeffHalf - 1)) >> FRACTION_BITS) & {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}}; -wire [COEFF_WIDTH-1:0] preCoeff01 = ((xBlend * (coeffOne - yBlend) + (coeffHalf - 1)) >> FRACTION_BITS) & {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}}; -wire [COEFF_WIDTH-1:0] preCoeff10 = (((coeffOne - xBlend) * yBlend + (coeffHalf - 1)) >> FRACTION_BITS) & {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}}; - -//Compute the coefficients -always @(posedge clk or posedge rst) -begin - if(rst) - begin - coeff00 <= 0; - coeff01 <= 0; - coeff10 <= 0; - coeff11 <= 0; - xBlend <= 0; - end - else - begin - xBlend <= {1'b0, xScaleAmount[SCALE_FRAC_BITS-1:SCALE_FRAC_BITS-FRACTION_BITS]}; //Changed to registered to improve timing - - if(nearestNeighbor == 1'b0) - begin - //Normal bilinear interpolation - coeff00 <= preCoeff00; - coeff01 <= preCoeff01; - coeff10 <= preCoeff10; - coeff11 <= ((xBlend * yBlend + (coeffHalf - 1)) >> FRACTION_BITS) & {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}}; - //coeff11 <= coeffOne - preCoeff00 - preCoeff01 - preCoeff10; //Guarantee that all coefficients sum to coeffOne. Saves a multiply too. Reverted to previous method due to timing issues. - end - else - begin - //Nearest neighbor interploation, set one coefficient to 1.0, the rest to zero based on the fractions - coeff00 <= xBlend < coeffHalf && yBlend < coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}}; - coeff01 <= xBlend >= coeffHalf && yBlend < coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}}; - coeff10 <= xBlend < coeffHalf && yBlend >= coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}}; - coeff11 <= xBlend >= coeffHalf && yBlend >= coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}}; - end - end -end - - -//Generate the blending multipliers -reg [(DATA_WIDTH+COEFF_WIDTH)*CHANNELS-1:0] product00, product01, product10, product11; - -generate -genvar channel; - for(channel = 0; channel < CHANNELS; channel = channel + 1) - begin : blend_mult_generate - always @(posedge clk or posedge rst) - begin - if(rst) - begin - //productxx[channel] <= 0; - product00[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0; - product01[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0; - product10[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0; - product11[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0; - - //readDataxxReg[channel] <= 0; - readData00Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0; - readData01Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0; - readData10Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0; - readData11Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0; - - //dOut[channel] <= 0; - dOut[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0; - end - else - begin - //readDataxxReg[channel] <= readDataxx[channel]; - readData00Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData00[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ]; - readData01Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData01[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ]; - readData10Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData10[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ]; - readData11Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData11[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ]; - - //productxx[channel] <= readDataxxReg[channel] * coeffxx - product00[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData00Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff00; - product01[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData01Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff01; - product10[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData10Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff10; - product11[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData11Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff11; - - //dOut[channel] <= (((product00[channel]) + - // (product01[channel]) + - // (product10[channel]) + - // (product11[channel])) >> FRACTION_BITS) & ({ {COEFF_WIDTH{1'b0}}, {DATA_WIDTH{1'b1}} }); - dOut[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= - (((product00[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel]) + - (product01[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel]) + - (product10[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel]) + - (product11[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel])) >> FRACTION_BITS) & ({ {COEFF_WIDTH{1'b0}}, {DATA_WIDTH{1'b1}} }); - end - end - end -endgenerate - - -//---------------------------Data write logic---------------------------------- -//Places input data into the correct ram in the RFIFO (ram FIFO) -//Controls writing to the RFIFO, and discards lines that arn't used - -reg [INPUT_Y_RES_WIDTH-1:0] writeNextValidLine; //Which line greater than writeRowCount is the next one that must be read in -reg [INPUT_Y_RES_WIDTH-1:0] writeNextPlusOne; //One greater than writeNextValidLine, because we must always read in two adjacent lines -reg [INPUT_Y_RES_WIDTH-1:0] writeRowCount; //Which line we're reading from dIn -reg [OUTPUT_Y_RES_WIDTH-1:0] writeOutputLine; //The output line that corresponds to the input line. This is incremented until writeNextValidLine is greater than writeRowCount -reg getNextPlusOne; //Flag so that writeNextPlusOne is captured only once after writeRowCount >= writeNextValidLine. This is in case multiple cycles are requred until writeNextValidLine changes. - -//Determine which lines to read out and which to discard. -//writeNextValidLine is the next valid line number that needs to be read out above current value writeRowCount -//writeNextPlusOne also needs to be read out (to do interpolation), this may or may not be equal to writeNextValidLine -always @(posedge clk or posedge rst or posedge start) -begin - if(rst | start) - begin - writeOutputLine <= 0; - writeNextValidLine <= 0; - writeNextPlusOne <= 1; - getNextPlusOne <= 1; - end - else - begin - if(writeRowCount >= writeNextValidLine) //When writeRowCount becomes higher than the next valid line to read out, comptue the next valid line. - begin - if(getNextPlusOne) //Keep writeNextPlusOne - begin - writeNextPlusOne <= writeNextValidLine + 1; - end - getNextPlusOne <= 0; - writeOutputLine <= writeOutputLine + 1; - writeNextValidLine <= ((writeOutputLine*yScale + {{(OUTPUT_Y_RES_WIDTH + SCALE_INT_BITS){1'b0}}, topFracOffset}) >> SCALE_FRAC_BITS) & {{SCALE_BITS{1'b0}}, {OUTPUT_Y_RES_WIDTH{1'b1}}}; - end - else - begin - getNextPlusOne <= 1; - end - end -end - -reg discardInput; -reg [DISCARD_CNT_WIDTH-1:0] discardCountReg; -wire advanceWrite; - -reg [1:0] writeState; - -reg [INPUT_X_RES_WIDTH-1:0] writeColCount; -reg enableNextDin; -reg forceRead; - -//Write state machine -//Controls writing scaler input data into the RRB - -parameter WS_START = 0; -parameter WS_DISCARD = 1; -parameter WS_READ = 2; -parameter WS_DONE = 3; - -//Control write and address signals to write data into ram FIFO -always @ (posedge clk or posedge rst or posedge start) -begin - if(rst | start) - begin - writeState <= WS_START; - enableNextDin <= 0; - discardInput <= 0; - readyForRead <= 0; - writeRowCount <= 0; - writeColCount <= 0; - discardCountReg <= 0; - forceRead <= 0; - end - else - begin - case (writeState) - - WS_START: - begin - discardCountReg <= inputDiscardCnt; - if(inputDiscardCnt > 0) - begin - discardInput <= 1; - enableNextDin <= 1; - writeState <= WS_DISCARD; - end - else - begin - discardInput <= 0; - enableNextDin <= 1; - writeState <= WS_READ; - end - discardInput <= (inputDiscardCnt > 0) ? 1'b1 : 1'b0; - end - - WS_DISCARD: //Discard pixels from input data - begin - if(dInValid) - begin - discardCountReg <= discardCountReg - 1; - if((discardCountReg - 1) == 0) - begin - discardInput <= 0; - writeState <= WS_READ; - end - end - end - - WS_READ: - begin - if(dInValid & nextDin) - begin - if(writeColCount == inputXRes) - begin //Occurs on the last pixel in the line - if((writeNextValidLine == writeRowCount + 1) || - (writeNextPlusOne == writeRowCount + 1)) - begin //Next line is valid, write into buffer - discardInput <= 0; - end - else - begin //Next line is not valid, discard - discardInput <= 1; - end - - //Once writeRowCount is >= 2, data is ready to start being output. - if(writeRowCount[1]) - readyForRead <= 1; - - if(writeRowCount == inputYRes) //When all data has been read in, stop reading. - begin - writeState <= WS_DONE; - enableNextDin <= 0; - forceRead <= 1; - end - - writeColCount <= 0; - writeRowCount <= writeRowCount + 1; - end - else - begin - writeColCount <= writeColCount + 1; - end - end - end - - WS_DONE: - begin - //do nothing, wait for reset - end - - endcase - end -end - - -//Advance write whenever we have just written a valid line (discardInput == 0) -//Generate this signal one earlier than discardInput above that uses the same conditions, to advance the buffer at the right time. -assign advanceWrite = (writeColCount == inputXRes) & (discardInput == 0) & dInValid & nextDin; -assign allDataWritten = writeState == WS_DONE; -assign nextDin = (fillCount < BUFFER_SIZE) & enableNextDin; - -ramFifo #( - .DATA_WIDTH( DATA_WIDTH*CHANNELS ), - .ADDRESS_WIDTH( INPUT_X_RES_WIDTH ), //Controls width of RAMs - .BUFFER_SIZE( BUFFER_SIZE ) //Number of RAMs -) ramRB ( - .clk( clk ), - .rst( rst | start ), - .advanceRead1( advanceRead1 ), - .advanceRead2( advanceRead2 ), - .advanceWrite( advanceWrite ), - .forceRead( forceRead ), - - .writeData( dIn ), - .writeAddress( writeColCount ), - .writeEnable( dInValid & nextDin & enableNextDin & ~discardInput ), - .fillCount( fillCount ), - - .readData00( readData00 ), - .readData01( readData01 ), - .readData10( readData10 ), - .readData11( readData11 ), - .readAddress( readAddress ) -); - -endmodule //scaler - - - -//---------------------------Ram FIFO (RFIFO)----------------------------- -//FIFO buffer with rams as the elements, instead of data -//One ram is filled, while two others are simultaneously read out. -//Four neighboring pixels are read out at once, at the selected RAM and one line down, and at readAddress and readAddress + 1 -module ramFifo #( - parameter DATA_WIDTH = 8, - parameter ADDRESS_WIDTH = 8, - parameter BUFFER_SIZE = 2, - parameter BUFFER_SIZE_WIDTH = ((BUFFER_SIZE+1) <= 2) ? 1 : //wide enough to hold value BUFFER_SIZE + 1 - ((BUFFER_SIZE+1) <= 4) ? 2 : - ((BUFFER_SIZE+1) <= 8) ? 3 : - ((BUFFER_SIZE+1) <= 16) ? 4 : - ((BUFFER_SIZE+1) <= 32) ? 5 : - ((BUFFER_SIZE+1) <= 64) ? 6 : 7 -)( - input wire clk, - input wire rst, - input wire advanceRead1, //Advance selected read RAM by one - input wire advanceRead2, //Advance selected read RAM by two - input wire advanceWrite, //Advance selected write RAM by one - input wire forceRead, //Disables writing to allow all data to be read out (RAM being written to cannot be read from normally) - - input wire [DATA_WIDTH-1:0] writeData, - input wire [ADDRESS_WIDTH-1:0] writeAddress, - input wire writeEnable, - output reg [BUFFER_SIZE_WIDTH-1:0] - fillCount, - - // yx - output wire [DATA_WIDTH-1:0] readData00, //Read from deepest RAM (earliest data), at readAddress - output wire [DATA_WIDTH-1:0] readData01, //Read from deepest RAM (earliest data), at readAddress + 1 - output wire [DATA_WIDTH-1:0] readData10, //Read from second deepest RAM (second earliest data), at readAddress - output wire [DATA_WIDTH-1:0] readData11, //Read from second deepest RAM (second earliest data), at readAddress + 1 - input wire [ADDRESS_WIDTH-1:0] readAddress -); - -reg [BUFFER_SIZE-1:0] writeSelect; -reg [BUFFER_SIZE-1:0] readSelect; - -//Read select ring register -always @(posedge clk or posedge rst) -begin - if(rst) - readSelect <= 1; - else - begin - if(advanceRead1) - begin - readSelect <= {readSelect[BUFFER_SIZE-2 : 0], readSelect[BUFFER_SIZE-1]}; - end - else if(advanceRead2) - begin - readSelect <= {readSelect[BUFFER_SIZE-3 : 0], readSelect[BUFFER_SIZE-1:BUFFER_SIZE-2]}; - end - end -end - -//Write select ring register -always @(posedge clk or posedge rst) -begin - if(rst) - writeSelect <= 1; - else - begin - if(advanceWrite) - begin - writeSelect <= {writeSelect[BUFFER_SIZE-2 : 0], writeSelect[BUFFER_SIZE-1]}; - end - end -end - -wire [DATA_WIDTH-1:0] ramDataOutA [2**BUFFER_SIZE-1:0]; -wire [DATA_WIDTH-1:0] ramDataOutB [2**BUFFER_SIZE-1:0]; - -//Generate to instantiate the RAMs -generate -genvar i; - for(i = 0; i < BUFFER_SIZE; i = i + 1) - begin : ram_generate - - ramDualPort #( - .DATA_WIDTH( DATA_WIDTH ), - .ADDRESS_WIDTH( ADDRESS_WIDTH ) - ) ram_inst_i( - .clk( clk ), - - //Port A is written to as well as read from. When writing, this port cannot be read from. - //As long as the buffer is large enough, this will not cause any problem. - .addrA( ((writeSelect[i] == 1'b1) && !forceRead && writeEnable) ? writeAddress : readAddress ), //&& writeEnable is - //to allow the full buffer to be used. After the buffer is filled, write is advanced, so writeSelect - //and readSelect are the same. The full buffer isn't written to, so this allows the read to work properly. - .dataA( writeData ), - .weA( ((writeSelect[i] == 1'b1) && !forceRead) ? writeEnable : 1'b0 ), - .qA( ramDataOutA[2**i] ), - - .addrB( readAddress + 1 ), - .dataB( 0 ), - .weB( 1'b0 ), - .qB( ramDataOutB[2**i] ) - ); - end -endgenerate - -//Select which ram to read from -wire [BUFFER_SIZE-1:0] readSelect0 = readSelect; -wire [BUFFER_SIZE-1:0] readSelect1 = (readSelect << 1) | readSelect[BUFFER_SIZE-1]; - -//Steer the output data to the right ports -assign readData00 = ramDataOutA[readSelect0]; -assign readData10 = ramDataOutA[readSelect1]; -assign readData01 = ramDataOutB[readSelect0]; -assign readData11 = ramDataOutB[readSelect1]; - -//Keep track of fill level -always @(posedge clk or posedge rst) -begin - if(rst) - begin - fillCount <= 0; - end - else - begin - if(advanceWrite) - begin - if(advanceRead1) - fillCount <= fillCount; - else if(advanceRead2) - fillCount <= fillCount - 1; - else - fillCount <= fillCount + 1; - end - else - begin - if(advanceRead1) - fillCount <= fillCount - 1; - else if(advanceRead2) - fillCount <= fillCount - 2; - else - fillCount <= fillCount; - end - end -end - -endmodule //ramFifo - - -//Dual port RAM -module ramDualPort #( - parameter DATA_WIDTH = 8, - parameter ADDRESS_WIDTH = 8 -)( - input wire [(DATA_WIDTH-1):0] dataA, dataB, - input wire [(ADDRESS_WIDTH-1):0] addrA, addrB, - input wire weA, weB, clk, - output reg [(DATA_WIDTH-1):0] qA, qB -); - - // Declare the RAM variable - reg [DATA_WIDTH-1:0] ram[2**ADDRESS_WIDTH-1:0]; - - //Port A - always @ (posedge clk) - begin - if (weA) - begin - ram[addrA] <= dataA; - qA <= dataA; - end - else - begin - qA <= ram[addrA]; - end - end - - //Port B - always @ (posedge clk) - begin - if (weB) - begin - ram[addrB] <= dataB; - qB <= dataB; - end - else - begin - qB <= ram[addrB]; - end - end - -endmodule //ramDualPort diff --git a/Scaler/sim/out/output1280x1024to640x512.raw b/Scaler/sim/out/output1280x1024to640x512.raw deleted file mode 100644 index 89cfb06..0000000 Binary files a/Scaler/sim/out/output1280x1024to640x512.raw and /dev/null differ diff --git a/Scaler/sim/out/output640x512to1280x1024.raw b/Scaler/sim/out/output640x512to1280x1024.raw deleted file mode 100644 index 38a7f8d..0000000 Binary files a/Scaler/sim/out/output640x512to1280x1024.raw and /dev/null differ diff --git a/Scaler/sim/out/output640x512to640x512.raw b/Scaler/sim/out/output640x512to640x512.raw deleted file mode 100644 index f2e60ae..0000000 Binary files a/Scaler/sim/out/output640x512to640x512.raw and /dev/null differ diff --git a/Scaler/sim/scaler_tb.v b/Scaler/sim/scaler_tb.v deleted file mode 100644 index b6e98c3..0000000 --- a/Scaler/sim/scaler_tb.v +++ /dev/null @@ -1,437 +0,0 @@ -/*----------------------------------------------------------------------------- - - Video Stream Scaler testbench - - Author: David Kronstein - - - -Copyright 2011, David Kronstein, and individual contributors as indicated -by the @authors tag. - -This is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation; either version 2.1 of -the License, or (at your option) any later version. - -This software is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this software; if not, write to the Free -Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -02110-1301 USA, or see the FSF site: http://www.fsf.org. - -------------------------------------------------------------------------------- - -Testbench for streamScaler V1.0.0 - -*/ - -`default_nettype none - -//Input files. Raw data format, no header. 8 bits per pixel, 3 color channels. -`define INPUT640x512 "src/input640x512RGB.raw" -`define INPUT1280x1024 "src/input1280x1024RGB.raw" -`define INPUT1280x1024_21EXTRA "src/input640x512_21extraRGB.raw" //21 extra pixels at the start to be discarded - -module scalerTestbench; -parameter BUFFER_SIZE = 4; - -wire [7-1:0] done; - -//640x512 to 1280x1024 - scalerTest #( - .INPUT_X_RES ( 640-1 ), - .INPUT_Y_RES ( 512-1 ), - .OUTPUT_X_RES ( 1280-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 1024-1 ), //Output resolution - 1 - //.X_SCALE ( X_SCALE ), - //.Y_SCALE ( Y_SCALE ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 8 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_640x512to1280x1024 ( - .inputFilename( `INPUT640x512 ), - .outputFilename( "out/output640x512to1280x1024.raw" ), - - //Control - .inputDiscardCnt( 0 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( 0 ), - .topFracOffset( 0 ), - .nearestNeighbor( 0 ), - .done ( done[0] ) - ); - - -//640x512 to 640x512 - scalerTest #( - .INPUT_X_RES ( 640-1 ), - .INPUT_Y_RES ( 512-1 ), - .OUTPUT_X_RES ( 640-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 512-1 ), //Output resolution - 1 - .X_SCALE ( 32'h4000 ), - .Y_SCALE ( 32'h4000 ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 8 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_640x512to640x512 ( - .inputFilename( `INPUT640x512 ), - .outputFilename( "out/output640x512to640x512.raw" ), - - //Control - .inputDiscardCnt( 0 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( 0 ), - .topFracOffset( 0 ), - .nearestNeighbor( 0 ), - .done ( done[1] ) - ); - - -//1280x1024 to 960x768 - scalerTest #( - .INPUT_X_RES ( 1280-1 ), - .INPUT_Y_RES ( 1024-1 ), - .OUTPUT_X_RES ( 960-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 768-1 ), //Output resolution - 1 - //.X_SCALE ( X_SCALE ), - //.Y_SCALE ( Y_SCALE ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 8 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_1280x1024to960x768 ( - .inputFilename( `INPUT1280x1024 ), - .outputFilename( "out/output1280x1024to960x768.raw" ), - - //Control - .inputDiscardCnt( 0 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( 0 ), - .topFracOffset( 0 ), - .nearestNeighbor( 0 ), - .done ( done[2] ) - ); - - -//1280x1024 to 640x512 - scalerTest #( - .INPUT_X_RES ( 1280-1 ), - .INPUT_Y_RES ( 1024-1 ), - .OUTPUT_X_RES ( 640-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 512-1 ), //Output resolution - 1 - .X_SCALE ( 32'h4000*2 ), - .Y_SCALE ( 32'h4000*2 ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 8 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_1280x1024to640x512 ( - .inputFilename( `INPUT1280x1024 ), - .outputFilename( "out/output1280x1024to640x512.raw" ), - - //Control - .inputDiscardCnt( 0 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( 25'h1FFF ), - .topFracOffset( 25'h1FFF ), - .nearestNeighbor( 0 ), - .done ( done[3] ) - ); - -//1280x1024 to 480x384 - - scalerTest #( - .INPUT_X_RES ( 1280-1 ), - .INPUT_Y_RES ( 1024-1 ), - .OUTPUT_X_RES ( 480-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 384-1 ), //Output resolution - 1 - //.X_SCALE ( 32'h4000*2 ), - //.Y_SCALE ( 32'h4000*2 ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 8 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_1280x1024to480x384 ( - .inputFilename( `INPUT1280x1024 ), - .outputFilename( "out/output1280x1024to480x384.raw" ), - - //Control - .inputDiscardCnt( 0 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( 0 ), - .topFracOffset( 0 ), - .nearestNeighbor( 0 ), - .done ( done[4] ) - ); - -//640x512 to 1280x1024, discarding 21 - - scalerTest #( - .INPUT_X_RES ( 640-1 ), - .INPUT_Y_RES ( 512-1 ), - .OUTPUT_X_RES ( 1280-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 1024-1 ), //Output resolution - 1 - //.X_SCALE ( 32'h4000*2 ), - //.Y_SCALE ( 32'h4000*2 ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 8 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_640x512to1280x1024_21extra ( - .inputFilename( `INPUT1280x1024_21EXTRA ), - .outputFilename( "out/output640x512to1280x1024_21extra.raw" ), - - //Control - .inputDiscardCnt( 21 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( 0 ), - .topFracOffset( 0 ), - .nearestNeighbor( 0 ), - .done ( done[5] ) - ); - -//640x512 to 1280x1024, discarding 21 - - scalerTest #( - .INPUT_X_RES ( 640-1 ), - .INPUT_Y_RES ( 40-1 ), - .OUTPUT_X_RES ( 640-1 ), //Output resolution - 1 - .OUTPUT_Y_RES ( 512-1 ), //Output resolution - 1 - .X_SCALE ( 32'h4000 * (50-1) / (640-1)-1 ), - .Y_SCALE ( 32'h4000 * (40-1) / (512-1)-1 ), - - .DATA_WIDTH ( 8 ), - .DISCARD_CNT_WIDTH ( 14 ), - .INPUT_X_RES_WIDTH ( 11 ), - .INPUT_Y_RES_WIDTH ( 11 ), - .OUTPUT_X_RES_WIDTH ( 11 ), - .OUTPUT_Y_RES_WIDTH ( 11 ), - .BUFFER_SIZE ( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer - ) st_50x40to640x512clipped ( - .inputFilename( `INPUT640x512 ), - .outputFilename( "out/output50x40to640x512clipped.raw" ), - - //Control - .inputDiscardCnt( 640*3 ), //Number of input pixels to discard before processing data. Used for clipping - .leftOffset( {11'd249, 14'b0} ), - .topFracOffset( 0 ), - .nearestNeighbor( 0 ), - .done ( done[6] ) - ); - - initial - begin - #10 - while(done != 7'b1111111) - #10 - ; - $stop; - end - - - - -endmodule - -module scalerTest #( -parameter INPUT_X_RES = 120-1, -parameter INPUT_Y_RES = 90-1, -parameter OUTPUT_X_RES = 1280-1, //Output resolution - 1 -parameter OUTPUT_Y_RES = 960-1, //Output resolution - 1 -parameter X_SCALE = 32'h4000 * (INPUT_X_RES) / (OUTPUT_X_RES)-1, -parameter Y_SCALE = 32'h4000 * (INPUT_Y_RES) / (OUTPUT_Y_RES)-1, - -parameter DATA_WIDTH = 8, -parameter CHANNELS = 3, -parameter DISCARD_CNT_WIDTH = 8, -parameter INPUT_X_RES_WIDTH = 11, -parameter INPUT_Y_RES_WIDTH = 11, -parameter OUTPUT_X_RES_WIDTH = 11, -parameter OUTPUT_Y_RES_WIDTH = 11, -parameter BUFFER_SIZE = 6 //Number of RAMs in RAM ring buffer -)( -input wire [50*8:0] inputFilename, outputFilename, - -//Control -input wire [DISCARD_CNT_WIDTH-1:0] inputDiscardCnt, //Number of input pixels to discard before processing data. Used for clipping -input wire [INPUT_X_RES_WIDTH+14-1:0] leftOffset, -input wire [14-1:0] topFracOffset, -input wire nearestNeighbor, - -output reg done - -); - - -reg clk; -reg rst; - - -reg [DATA_WIDTH*CHANNELS-1:0] dIn; -reg dInValid; -wire nextDin; -reg start; - -wire [DATA_WIDTH*CHANNELS-1:0] dOut; -wire dOutValid; -reg nextDout; - -integer r, rfile, wfile; - -initial // Clock generator - begin - #10 //Delay to allow filename to get here - clk = 0; - #5 forever #5 clk = !clk; - end - -initial // Reset - begin - done = 0; - #10 //Delay to allow filename to get here - rst = 0; - #5 rst = 1; - #4 rst = 0; - // #50000 $stop; - end - -reg eof; -reg [DATA_WIDTH*CHANNELS-1:0] readMem [0:0]; -initial // Input file read, generates dIn data -begin - #10 //Delay to allow filename to get here - rfile = $fopen(inputFilename, "rb"); - - dIn = 0; - dInValid = 0; - start = 0; - - #41 - start = 1; - - #10 - start = 0; - - #20 - r = $fread(readMem, rfile); - dIn = readMem[0]; - - while(! $feof(rfile)) - begin - dInValid = 1; - - #10 - if(nextDin) - begin - r = $fread(readMem, rfile); - dIn = readMem[0]; - end - end - - $fclose(rfile); -end - -//Generate nextDout request signal -initial -begin - #10 //Delay to match filename arrival delay - nextDout = 0; - #140001 - forever - begin - //This can be used to slow down the read to simulate live read-out. This basically inserts H blank periods. - #(10*(OUTPUT_X_RES+1)*4) - nextDout = 0; - #(10*(OUTPUT_X_RES+1)) - nextDout = 1; - - end -end - -//Read dOut and write to file -integer dOutCount; -initial -begin - #10 //Delay to allow filename to get here - wfile = $fopen(outputFilename, "wb"); - nextDout = 0; - dOutCount = 0; - #1 - while(dOutCount < (OUTPUT_X_RES+1) * (OUTPUT_Y_RES+1)) - begin - #10 - if(dOutValid == 1) - begin - $fwrite(wfile, "%c", dOut[23:16]); - $fwrite(wfile, "%c", dOut[15:8]); - $fwrite(wfile, "%c", dOut[7:0]); - dOutCount = dOutCount + 1; - end - end - $fclose(wfile); - done = 1; -end - -streamScaler #( -.DATA_WIDTH( DATA_WIDTH ), -.CHANNELS( CHANNELS ), -.DISCARD_CNT_WIDTH( DISCARD_CNT_WIDTH ), -.INPUT_X_RES_WIDTH( INPUT_X_RES_WIDTH ), -.INPUT_Y_RES_WIDTH( INPUT_Y_RES_WIDTH ), -.OUTPUT_X_RES_WIDTH( OUTPUT_X_RES_WIDTH ), -.OUTPUT_Y_RES_WIDTH( OUTPUT_Y_RES_WIDTH ), -.BUFFER_SIZE( BUFFER_SIZE ) //Number of RAMs in RAM ring buffer -) scaler_inst ( -.clk( clk ), -.rst( rst ), - -.dIn( dIn ), -.dInValid( dInValid ), -.nextDin( nextDin ), -.start( start ), - -.dOut( dOut ), -.dOutValid( dOutValid ), -.nextDout( nextDout ), - -//Control -.inputDiscardCnt( inputDiscardCnt ), //Number of input pixels to discard before processing data. Used for clipping -.inputXRes( INPUT_X_RES ), //Input data number of pixels per line -.inputYRes( INPUT_Y_RES ), - -.outputXRes( OUTPUT_X_RES ), //Resolution of output data -.outputYRes( OUTPUT_Y_RES ), -.xScale( X_SCALE ), //Scaling factors. Input resolution scaled by 1/xScale. Format Q4.14 -.yScale( Y_SCALE ), //Scaling factors. Input resolution scaled by 1/yScale. Format Q4.14 - -.leftOffset( leftOffset ), -.topFracOffset( topFracOffset ), -.nearestNeighbor( nearestNeighbor ) -); - -endmodule diff --git a/devenv.lock b/devenv.lock deleted file mode 100644 index ad4acbd..0000000 --- a/devenv.lock +++ /dev/null @@ -1,122 +0,0 @@ -{ - "nodes": { - "devenv": { - "locked": { - "dir": "src/modules", - "lastModified": 1725637114, - "owner": "cachix", - "repo": "devenv", - "rev": "c31e347a96dbb7718a0279afa993752a7dfc6a39", - "treeHash": "e0dfcbbfb0974603336900406b364bd4d1308fa4", - "type": "github" - }, - "original": { - "dir": "src/modules", - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1716977621, - "owner": "cachix", - "repo": "devenv-nixpkgs", - "rev": "4267e705586473d3e5c8d50299e71503f16a6fb6", - "treeHash": "6d9f1f7ca0faf1bc2eeb397c78a49623260d3412", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "rolling", - "repo": "devenv-nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1725693463, - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "68e7dce0a6532e876980764167ad158174402c6f", - "treeHash": "ee872ee4d2426a6c3e1e4b3fa844550ce1b52b29", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1725513492, - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "7570de7b9b504cfe92025dd1be797bf546f66528", - "treeHash": "4b46d77870afecd8f642541cb4f4927326343b59", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "nixpkgs": "nixpkgs", - "pre-commit-hooks": "pre-commit-hooks" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/devenv.nix b/devenv.nix deleted file mode 100644 index f5e8f65..0000000 --- a/devenv.nix +++ /dev/null @@ -1,59 +0,0 @@ -{ pkgs, lib, config, inputs, ... }: - -{ - # https://devenv.sh/basics/ - env.GREET = "devenv"; - - # https://devenv.sh/packages/ - packages = with pkgs; [ - git - verilator - systemc - verible - svls - gtkwave - ]; - - # https://devenv.sh/languages/ - languages.rust.enable = true; - languages.c.enable = true; - languages.cplusplus.enable = true; - - # https://devenv.sh/processes/ - # processes.cargo-watch.exec = "cargo-watch"; - - # https://devenv.sh/services/ - # services.postgres.enable = true; - - # https://devenv.sh/scripts/ - scripts.addEnv.exec = '' - export SYSTEMC_INCLUDE="${pkgs.systemc}/include" - echo $SYSTEMC_INCLUDE - export SYSTEMC_LIBDIR="${pkgs.systemc}/lib" - echo $SYSTEMC_LIBDIR - ''; - - enterShell = '' - addEnv - echo - - git --version - echo - - verilator --version - echo - - gcc --version - ''; - - # https://devenv.sh/tests/ - enterTest = '' - echo "Running tests" - git --version | grep --color=auto "${pkgs.git.version}" - ''; - - # https://devenv.sh/pre-commit-hooks/ - # pre-commit.hooks.shellcheck.enable = true; - - # See full reference at https://devenv.sh/reference/options/ -} diff --git a/devenv.yaml b/devenv.yaml deleted file mode 100644 index 116a2ad..0000000 --- a/devenv.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json -inputs: - nixpkgs: - url: github:cachix/devenv-nixpkgs/rolling - -# If you're using non-OSS software, you can set allowUnfree to true. -# allowUnfree: true - -# If you're willing to use a package that's vulnerable -# permittedInsecurePackages: -# - "openssl-1.1.1w" - -# If you have more than one devenv you can merge them -#imports: -# - ./backend diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b6aa65a --- /dev/null +++ b/flake.lock @@ -0,0 +1,638 @@ +{ + "nodes": { + "cachix": { + "inputs": { + "devenv": "devenv_2", + "flake-compat": [ + "devenv", + "flake-compat" + ], + "git-hooks": [ + "devenv", + "pre-commit-hooks" + ], + "nixpkgs": [ + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724232775, + "narHash": "sha256-6u2DycIEgrgNYlLxyGqdFVmBNiKIitnQKJ1pbRP5oko=", + "owner": "cachix", + "repo": "cachix", + "rev": "03b6cb3f953097bff378fb8b9ea094bd091a4ec7", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "cachix", + "type": "github" + } + }, + "cachix_2": { + "inputs": { + "devenv": "devenv_3", + "flake-compat": [ + "devenv", + "cachix", + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "pre-commit-hooks": [ + "devenv", + "cachix", + "devenv", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1712055811, + "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", + "owner": "cachix", + "repo": "cachix", + "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "cachix", + "type": "github" + } + }, + "devenv": { + "inputs": { + "cachix": "cachix", + "flake-compat": "flake-compat_2", + "nix": "nix_3", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks_2" + }, + "locked": { + "lastModified": 1726063457, + "narHash": "sha256-VtMnPqbP2MLJSjEqmGEUb+cTG1dthc+Bfch2/McymbI=", + "owner": "cachix", + "repo": "devenv", + "rev": "39bf6ce569103c9390d37322daa59468c31b3ce7", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "devenv_2": { + "inputs": { + "cachix": "cachix_2", + "flake-compat": [ + "devenv", + "cachix", + "flake-compat" + ], + "nix": "nix_2", + "nixpkgs": [ + "devenv", + "cachix", + "nixpkgs" + ], + "pre-commit-hooks": [ + "devenv", + "cachix", + "git-hooks" + ] + }, + "locked": { + "lastModified": 1723156315, + "narHash": "sha256-0JrfahRMJ37Rf1i0iOOn+8Z4CLvbcGNwa2ChOAVrp/8=", + "owner": "cachix", + "repo": "devenv", + "rev": "ff5eb4f2accbcda963af67f1a1159e3f6c7f5f91", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "devenv_3": { + "inputs": { + "flake-compat": [ + "devenv", + "cachix", + "devenv", + "cachix", + "flake-compat" + ], + "nix": "nix", + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix", + "pre-commit-hooks": [ + "devenv", + "cachix", + "devenv", + "cachix", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1708704632, + "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", + "owner": "cachix", + "repo": "devenv", + "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "python-rewrite", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "devenv", + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "libgit2": { + "flake": false, + "locked": { + "lastModified": 1697646580, + "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=", + "owner": "libgit2", + "repo": "libgit2", + "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5", + "type": "github" + }, + "original": { + "owner": "libgit2", + "repo": "libgit2", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "cachix", + "devenv", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1688870561, + "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, + "nix_2": { + "inputs": { + "flake-compat": [ + "devenv", + "cachix", + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression_2" + }, + "locked": { + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nix_3": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "flake-parts": "flake-parts", + "libgit2": "libgit2", + "nixpkgs": "nixpkgs_2", + "nixpkgs-23-11": "nixpkgs-23-11", + "nixpkgs-regression": "nixpkgs-regression_3", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1725980365, + "narHash": "sha256-uDwWyizzlQ0HFzrhP6rVp2+2NNA+/TM5zT32dR8GUlg=", + "owner": "domenkozar", + "repo": "nix", + "rev": "1e61e9f40673f84c3b02573145492d8af581bec5", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.24", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1692808169, + "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-23-11": { + "locked": { + "lastModified": 1717159533, + "narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_2": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_3": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1717432640, + "narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "88269ab3044128b7c2f4c7d68448b2fb50456870", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 315532800, + "narHash": "sha256-DXLcxy2Vmxj0vD/GACAsw/JCeyi3UJlVl/9iU+ZnPnU=", + "type": "tarball", + "url": "https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable/nixexprs.tar.xz" + }, + "original": { + "type": "tarball", + "url": "https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable/nixexprs.tar.xz" + } + }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "cachix", + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1692876271, + "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "devenv", + "nix" + ], + "flake-utils": "flake-utils_2", + "gitignore": [ + "devenv", + "nix" + ], + "nixpkgs": [ + "devenv", + "nix", + "nixpkgs" + ], + "nixpkgs-stable": [ + "devenv", + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712897695, + "narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_2": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1725513492, + "narHash": "sha256-tyMUA6NgJSvvQuzB7A1Sf8+0XCHyfSPRx/b00o6K0uo=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "7570de7b9b504cfe92025dd1be797bf546f66528", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs_3" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f5fc646 --- /dev/null +++ b/flake.nix @@ -0,0 +1,28 @@ +{ + inputs = { + nixpkgs.url = "https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable/nixexprs.tar.xz"; + devenv.url = "github:cachix/devenv"; + devenv.inputs.nixpkgs.follows = "nixpkgs"; + }; + + nixConfig = { + extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw="; + trusted-substituters = "https://devenv.cachix.org"; + }; + + outputs = { self, nixpkgs, devenv, ... } @ inputs: + let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}; + in { + packages.${system}.devenv-up = self.devShells.${system}.default.config.procfileScript; + + devShells.${system}.default = devenv.lib.mkShell { + inherit inputs pkgs; + # Import devenv shell modules + modules = [ + ./FPGA.nix + ]; + }; + }; +} diff --git a/isp.sv b/isp.sv deleted file mode 100644 index fa3611d..0000000 --- a/isp.sv +++ /dev/null @@ -1,211 +0,0 @@ -`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校正 - GammaCorrection2 #( - .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/Color/ColorBlender.sv b/rtl/Color/ColorBlender.sv new file mode 100644 index 0000000..8923678 --- /dev/null +++ b/rtl/Color/ColorBlender.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/Color/GammaCorrection2.sv b/rtl/Color/GammaCorrection.sv old mode 100644 new mode 100755 similarity index 65% rename from Color/GammaCorrection2.sv rename to rtl/Color/GammaCorrection.sv index f5aa817..e098c09 --- a/Color/GammaCorrection2.sv +++ b/rtl/Color/GammaCorrection.sv @@ -1,8 +1,8 @@ `timescale 1ns / 1ps -module GammaCorrection2 #( +module GammaCorrection #( parameter reg [4:0] COLOR_DEPTH = 8 -) ( + ) ( input wire clk, input wire reset, @@ -18,31 +18,40 @@ module GammaCorrection2 #( input wire [7:0] gamma_table[256], input wire enable -); + ); reg [2:0] state, nextState; localparam reg [2:0] READ_DATA = 0; localparam reg [2:0] SEND_DATA = 2; reg [7:0] data_cache[3]; - always @(posedge clk) begin - if (reset) state <= READ_DATA; - else state <= nextState; + always @(posedge clk) + begin + if (reset) + state <= READ_DATA; + else + state <= nextState; end - always @(*) begin + always @(*) + begin case (state) - READ_DATA: nextState = in_en ? SEND_DATA : READ_DATA; - SEND_DATA: nextState = in_receive ? READ_DATA : SEND_DATA; - default: nextState = READ_DATA; + READ_DATA: + nextState = in_en ? SEND_DATA : READ_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 + always @(posedge clk) + begin + if (reset) + begin out_en <= 0; out_data[0] <= 0; out_data[1] <= 0; @@ -51,32 +60,44 @@ module GammaCorrection2 #( data_cache[0] <= 0; data_cache[1] <= 0; data_cache[2] <= 0; - end else begin + end + else + begin case (state) - READ_DATA: begin - if (in_en) begin + 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 + SEND_DATA: + begin + if (in_ready && !in_receive) + begin out_en <= 1; - if (enable) begin + 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 + 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 + else + out_en <= 0; end - default: ; + default: + ; endcase end end diff --git a/Color/GreyWorld.sv b/rtl/Color/GreyWorld.sv old mode 100644 new mode 100755 similarity index 100% rename from Color/GreyWorld.sv rename to rtl/Color/GreyWorld.sv diff --git a/Color/SaturationCorrection.sv b/rtl/Color/SaturationCorrection.sv similarity index 100% rename from Color/SaturationCorrection.sv rename to rtl/Color/SaturationCorrection.sv diff --git a/Color/WhiteBalance.sv b/rtl/Color/WhiteBalance.sv old mode 100644 new mode 100755 similarity index 100% rename from Color/WhiteBalance.sv rename to rtl/Color/WhiteBalance.sv diff --git a/rtl/Crop/Crop.sv b/rtl/Crop/Crop.sv new file mode 100644 index 0000000..b3afd55 --- /dev/null +++ b/rtl/Crop/Crop.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/Demosaic.sv b/rtl/Demosaic/Demosaic.sv new file mode 100644 index 0000000..e4d703b --- /dev/null +++ b/rtl/Demosaic/Demosaic.sv @@ -0,0 +1,112 @@ +`timescale 1ns / 1ps +module Demosaic #( +parameter WINDOW_LENGTH = 3, +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 // 输入/输出数据位宽 +)( + input wire clk, + input wire reset, + + input wire [DATA_WIDTH - 1:0] in_data [WINDOW_LENGTH*WINDOW_LENGTH], // 数据输入线.第一列数据在[0],[1],[2]中 + output reg [DATA_WIDTH - 1:0] out_data [3], // 数据输出线,3、2、1分别表示r、g、b + + input wire in_valid, + output wire out_valid, + + input wire in_ready, + output wire out_ready, + + output reg out_hsync, // 行同步,一行第一个像素点输出的同时高电平 + output reg out_fsync // 帧同步,一帧第一个像素点输出的同时高电平 +); + + localparam DATA_NUM = WINDOW_LENGTH*WINDOW_LENGTH; + localparam PIPILINE = 3; + + reg [PIPILINE-1:0] pipeline_valid; + wire pipeline_running; + assign pipeline_running = in_ready | ~pipeline_valid[PIPILINE-1]; + + //out_ready :只要本模块可以接收数据就一直拉高 + assign out_ready = pipeline_running; + //out_valid :只要本模块可以发出数据就一直拉高 + assign out_valid = pipeline_valid[PIPILINE-1]; + + reg [DATA_WIDTH-1:0] data_cache[DATA_NUM]; // 缓存颜色数据,行列nxn + reg [31:0] pos_x, pos_y, temp_pos_x, temp_pos_y; + reg [DATA_WIDTH-1:0] red, blue, green; + reg [1:0] raw_type; + + integer i; + always @(posedge clk) begin + if(reset) begin + for(i=0;i= TOTAL_WIDTH - 1)?(0):(pos_x + 1); + pos_y <= (pos_x >= TOTAL_WIDTH - 1)?((pos_y >= TOTAL_HEIGHT - 1)?(0):(pos_y + 1)):(pos_y); + end + + if(pipeline_valid[0]) begin + temp_pos_x <= pos_x; + temp_pos_y <= pos_y; + 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 + endcase + end + + if(pipeline_valid[1]) begin + {out_data[2],out_data[1],out_data[0]} <= {red,blue,green}; + out_hsync <= (temp_pos_x == 0); + out_fsync <= ((temp_pos_x == 0) && (temp_pos_y == 0)); + end + end + end + + // 0:gr 1:rg 2:bg 3:gb 窗口右移,0<->1 2<->3; 窗口下移,0<->2,1<->3。 + // bg gb gr rg + always @(*) begin + if(reset) raw_type = RAW_TYPE; + else case (RAW_TYPE) + 2'b00: raw_type = {pos_y[0], pos_x[0]}; + 2'b01: raw_type = {pos_y[0], ~pos_x[0]}; + 2'b10: raw_type = {~pos_y[0], pos_x[0]}; + 2'b11: raw_type = {~pos_y[0], ~pos_x[0]}; + endcase + end + +endmodule + diff --git a/RAM/DiffWidthSyncFIFO.sv b/rtl/RAM/DiffWidthSyncFIFO.sv old mode 100644 new mode 100755 similarity index 100% rename from RAM/DiffWidthSyncFIFO.sv rename to rtl/RAM/DiffWidthSyncFIFO.sv diff --git a/RAM/RGB_to_RAM.v b/rtl/RAM/RGB_to_RAM.v old mode 100644 new mode 100755 similarity index 100% rename from RAM/RGB_to_RAM.v rename to rtl/RAM/RGB_to_RAM.v diff --git a/RAM/SDRAM.v b/rtl/RAM/SDRAM.v old mode 100644 new mode 100755 similarity index 100% rename from RAM/SDRAM.v rename to rtl/RAM/SDRAM.v diff --git a/RAM/tb_DiffWidthSyncFIFO.sv b/rtl/RAM/tb_DiffWidthSyncFIFO.sv old mode 100644 new mode 100755 similarity index 100% rename from RAM/tb_DiffWidthSyncFIFO.sv rename to rtl/RAM/tb_DiffWidthSyncFIFO.sv diff --git a/rtl/Windows.sv b/rtl/Windows.sv new file mode 100644 index 0000000..d68b619 --- /dev/null +++ b/rtl/Windows.sv @@ -0,0 +1,56 @@ +`timescale 1ns / 1ps +module Windows #( +parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 +)( + // 基本信号 + input wire clk, + input wire reset, + // 数据线 + input wire [DATA_WIDTH - 1:0] in_data [3], // 0、1、2分别表示第一、二、三行 + output reg [DATA_WIDTH - 1:0] out_data [3*3], // 数据输出线 + // 有效信号 + input wire in_valid, // 上一模块输出数据有效 + output wire out_valid, // 当前模块输出数据有效 + // 准备信号 + input wire in_ready, // 下一模块可接受新数据 + output wire out_ready // 当前模块可接收新数据 +); + + localparam PIPILINE = 3; + + reg [PIPILINE-1:0] pipeline_valid; + + //out_ready :只要本模块可以接收数据就一直拉高 + assign out_ready = (pipeline_valid != {PIPILINE{1'b1}}) | ((pipeline_valid == {PIPILINE{1'b1}}) && in_ready); + //out_valid :只要本模块可以发出数据就一直拉高 + assign out_valid = (pipeline_valid == {PIPILINE{1'b1}}); + + integer i; + always @(posedge clk) begin + if(reset) begin + for(i=0;i<9;i=i+1) out_data[i] <= 0; + pipeline_valid <= 0; + end else begin + if((pipeline_valid != {PIPILINE{1'b1}}) || ((pipeline_valid == {PIPILINE{1'b1}}) && in_ready))begin + pipeline_valid[0] <= in_valid; + out_data[6] <= in_data[0]; + out_data[7] <= in_data[1]; + out_data[8] <= in_data[2]; + end + if((pipeline_valid[2] == 0) || (pipeline_valid[1] == 0) || ((pipeline_valid == {PIPILINE{1'b1}}) && in_ready))begin + pipeline_valid[1] <= pipeline_valid[0]; + out_data[3] <= out_data[6]; + out_data[4] <= out_data[7]; + out_data[5] <= out_data[8]; + end + if((pipeline_valid[2] == 0) || ((pipeline_valid == {PIPILINE{1'b1}}) && in_ready))begin + pipeline_valid[2] <= pipeline_valid[1]; + out_data[0] <= out_data[3]; + out_data[1] <= out_data[4]; + out_data[2] <= out_data[5]; + end + end + end + +endmodule + diff --git a/rtl/isp.sv b/rtl/isp.sv new file mode 100644 index 0000000..f83f180 --- /dev/null +++ b/rtl/isp.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_tb.sv new file mode 100644 index 0000000..900ca31 --- /dev/null +++ b/rtl/isp_tb.sv @@ -0,0 +1,110 @@ +`timescale 1ns / 1ps +module isp_tb(); + +parameter IN_WIDTH = 50; +parameter IN_HEIGHT = 50; +parameter OFFSET_X = 7; +parameter OFFSET_Y = 3; +parameter OUT_WIDTH = 30; +parameter OUT_HEIGHT = 30; +parameter COLOR_DEPTH = 8; +parameter RAW_TYPE = 3; + +reg clk; +initial clk = 0; +always #20 clk <= ~clk; + +reg[31:0] cnt_www; +reg reset; +initial begin + reset = 1; + cnt_www = 700; + #500 + reset = 0; + #5000000 + reset = 1; + cnt_www = 2000; + #500 + reset = 0; +end + +reg [15:0] in_data[3]; +wire [23:0]out_data; +reg in_valid; +wire out_valid; +reg in_ready; +wire out_ready; + +reg[31:0] cnt_valid, cnt_ready; +integer i; +always @(posedge clk) begin + if(reset) begin + in_valid <= 0; + in_ready <= 0; + cnt_valid <= 10; + cnt_ready <= 0; + for(i=0;i<3;i=i+1) in_data[i] <= 0; + end else begin + cnt_valid <= cnt_valid+1; + cnt_ready <= cnt_ready+1; + if(cnt_ready==cnt_www)begin + cnt_ready <= 0; + in_ready <= ~in_ready; + end + if(cnt_valid==500)begin + cnt_valid <= 200; + in_valid <= ~in_valid; + end + if(in_valid && out_ready)begin + in_data[0] <= in_data[0] + 1; + for(i=1;i<3;i=i+1) in_data[i] <= in_data[i-1]; + end + end +end + +reg [23:0] data_out_temp[8192*5]; +reg [31:0] now; +reg flag_ifdataerror; +always @(posedge clk) begin + if(reset) begin + flag_ifdataerror <= 0; + if(cnt_www==700) for(i=0;i<(1<<32);i=i+1) data_out_temp[i] <= 0; + now <= 0; + end else if(out_valid && in_ready)begin + now <= now + 1; + if(cnt_www==700)begin + data_out_temp[now] <= out_data; + end else if(cnt_www==2000)begin + flag_ifdataerror <= (data_out_temp[now] != out_data); + end else flag_ifdataerror <= flag_ifdataerror; + end +end + +isp_nofifo +#( + .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 ), + .RAW_TYPE (RAW_TYPE ) +) +u_isp( + .clk (clk ), + .reset (reset ), + .in_data (in_data ), + .out_data (out_data ), + .in_valid (in_valid ), + .out_valid (out_valid ), + .in_ready (in_ready ), + .out_ready (out_ready ), + .gain_red (50 ), + .gain_green (50 ), + .gain_blue (50 ), + .blender_enable (0 ) +); + + +endmodule \ No newline at end of file diff --git a/sim/sc_main.cpp b/sim/sc_main.cpp deleted file mode 100644 index ecdf1f8..0000000 --- a/sim/sc_main.cpp +++ /dev/null @@ -1,476 +0,0 @@ -// For std::unique_ptr -#include - -// SystemC global header -#include - -// Include common routines -#include // mkdir -#include -#include - -// Include model header, generated from Verilating "isp.v" -#include "Visp.h" - -// Handle file -#include -#include - -// math -#include - -#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; - -// 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_clk; - 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::unique_ptr out = std::make_unique(OUT_SIZE); - - SC_CTOR(TB_ISP) { - SC_CTHREAD(send_Data, clk.pos()); - reset_signal_is(reset, true); - - SC_CTHREAD(read_Data, im_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); - uint16_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); - // out_receceive.write(true); - - out[pos_y * OUT_WIDTH + pos_x] = im_data.read(); - - if (pos_x++ >= OUT_WIDTH) { - pos_x = 0; - pos_y++; - } - if (pos_y >= OUT_HEIGHT) { - pos_y = 0; - picProcess(out.get(), cnt_flame); - 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 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; - 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_clk(out_clk); - 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_clk(out_clk); - tb_isp.im_en(out_en); - tb_isp.im_data(out_data); - tb_isp.is_done(flag_done); - tb_isp.image = 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 - // 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/sim/software/test.RAW b/sim/software/test.RAW deleted file mode 100644 index 8e73d57..0000000 Binary files a/sim/software/test.RAW and /dev/null differ diff --git a/sim/software/demosaic.cpp b/src/pic_process/demosaic.cpp old mode 100644 new mode 100755 similarity index 99% rename from sim/software/demosaic.cpp rename to src/pic_process/demosaic.cpp index 3cb3112..f720fe3 --- a/sim/software/demosaic.cpp +++ b/src/pic_process/demosaic.cpp @@ -2,7 +2,7 @@ #include #include -#include "bmp.hpp" +#include "transform/bmp.hpp" enum BayerPattern { GRBG, RGGB, BGGR, GBRG }; const int IN_WIDTH = 1920; diff --git a/sim/software/demosaic2.cpp b/src/pic_process/demosaic2.cpp old mode 100644 new mode 100755 similarity index 99% rename from sim/software/demosaic2.cpp rename to src/pic_process/demosaic2.cpp index fcdf046..7a5dbb8 --- a/sim/software/demosaic2.cpp +++ b/src/pic_process/demosaic2.cpp @@ -2,7 +2,7 @@ #include #include -#include "bmp.hpp" +#include "transform/bmp.hpp" enum BayerPattern { GRBG, RGGB, BGGR, GBRG }; const int IN_WIDTH = 1936; diff --git a/src/sc_main.cpp b/src/sc_main.cpp new file mode 100644 index 0000000..4c92357 --- /dev/null +++ b/src/sc_main.cpp @@ -0,0 +1,23 @@ +// For std::unique_ptr +#include + +// SystemC global header +#include + +// Include common routines +#include // mkdir +#include +#include + +// Include model header, generated from Verilating "isp.v" +#include "obj_dir/Visp.h" +#include "tb_isp.hpp" + +// Read/Write Files +#include +#include + +int sc_main(int argc, const char** argv) { + + return 0; +} \ No newline at end of file diff --git a/src/sc_main.cpp.bak b/src/sc_main.cpp.bak new file mode 100755 index 0000000..a88581b --- /dev/null +++ b/src/sc_main.cpp.bak @@ -0,0 +1,471 @@ +// For std::unique_ptr +#include + +// SystemC global header +#include + +// Include common routines +#include // mkdir +#include +#include + +// Include model header, generated from Verilating "isp.v" +#include "Visp.h" + +// Handle file +#include +#include + +// math +#include + +#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; + +// 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_out out_valid; + sc_out out_data[3]; + + sc_in im_clk; + sc_in im_en; + sc_out out_ready; + sc_in im_data; + + sc_out is_done; + std::unique_ptr image = std::make_unique(IN_SIZE); + std::unique_ptr out = std::make_unique(OUT_SIZE); + + SC_CTOR(TB_ISP) { + SC_CTHREAD(send_Data, clk.pos()); + reset_signal_is(reset, true); + + SC_CTHREAD(read_Data, im_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_valid.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_valid.write(0); + } + + wait(); + } + } + + void read_Data(void) { + is_done.write(0); + uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; + uint32_t last_data = 0, cnt = 0; + bool is_finish = 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(); + + pos_x++; + if (pos_x >= IN_WIDTH) { + pos_x = 0; + pos_y++; + } + if (pos_y >= IN_HEIGHT - 2) { + pos_y = 0; + cnt_flame++; + } + } + } + else { + out_ready.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 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; + 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_valid; + sc_signal in_ready; + sc_signal in_data[3]; + + sc_signal out_clk; + sc_signal out_valid; + 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 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); + + 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.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); + + // 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 + // 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/tb_isp.cpp b/src/tb_isp.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/tb_isp.hpp b/src/tb_isp.hpp new file mode 100644 index 0000000..9b43428 --- /dev/null +++ b/src/tb_isp.hpp @@ -0,0 +1,24 @@ +#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/sim/bmp.cpp b/src/transform/bmp.cpp old mode 100644 new mode 100755 similarity index 100% rename from sim/bmp.cpp rename to src/transform/bmp.cpp diff --git a/sim/bmp.hpp b/src/transform/bmp.hpp old mode 100644 new mode 100755 similarity index 100% rename from sim/bmp.hpp rename to src/transform/bmp.hpp diff --git a/sim/transform/im.tif b/src/transform/im.tif old mode 100644 new mode 100755 similarity index 100% rename from sim/transform/im.tif rename to src/transform/im.tif diff --git a/sim/transform/raw_cut.py b/src/transform/raw_cut.py old mode 100644 new mode 100755 similarity index 100% rename from sim/transform/raw_cut.py rename to src/transform/raw_cut.py diff --git a/xmake.lua b/xmake.lua index e69de29..c2dddab 100644 --- a/xmake.lua +++ b/xmake.lua @@ -0,0 +1,15 @@ +--- Generate compile_commands.json for clangd language server +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)") +) + +target("TB_ISP") + set_toolchains("gcc") + --- C/C++ Codes + add_files( + "src/**.cpp" + ) + --- Include directories + add_includedirs("src", ".", INCLUDE_DIRS) \ No newline at end of file