`timescale 1ns/1ps

module TB_ISP ();

parameter    Pe_CLK = 8 ;

parameter H_ACTIVE = 16'd1024;
parameter H_FP = 16'd24;      
parameter H_SYNC = 16'd136;   
parameter H_BP = 16'd160;  
//parameter H_FP = 16'd1;      
//parameter H_SYNC = 16'd1;   
//parameter H_BP = 16'd1;   
parameter V_ACTIVE = 16'd768; 
parameter V_FP  = 16'd3;      
parameter V_SYNC  = 16'd6;    
parameter V_BP  = 16'd29;     
//parameter V_FP  = 16'd1;      
//parameter V_SYNC  = 16'd1;    
//parameter V_BP  = 16'd1;     
parameter HS_POL = 1'b0;
parameter VS_POL = 1'b0;

parameter H_TOTAL = H_ACTIVE + H_FP + H_SYNC + H_BP;//horizontal total time (pixels)
parameter V_TOTAL = V_ACTIVE + V_FP + V_SYNC + V_BP;//vertical total time (lines)

reg hs_reg;                      //horizontal sync register
reg vs_reg;                      //vertical sync register
reg hs_reg_d0;                   //delay 1 clock of 'hs_reg'
reg vs_reg_d0;                   //delay 1 clock of 'vs_reg'
reg h_active;                    //horizontal video active
reg v_active;                    //vertical video active
reg video_active_d0;             //delay 1 clock of video_active

wire video_active;               //video active(horizontal active and vertical active)
wire hs          ;
wire vs          ;
wire de          ;

reg      [11:0]       v_cnt   ; 
reg      [11:0]       h_cnt   ; 

assign hs = hs_reg_d0;
assign vs = vs_reg_d0;
assign video_active = h_active & v_active;
assign de = video_active_d0;

reg            pixelclk    ;
reg            rst_n       ;

wire   [23:0]  VGA_rgb     ;
wire           VGA_hsync   ;
wire           VGA_vsync   ;
wire           VGA_de      ;


wire   clk ;
wire   rst ;
assign clk = pixelclk ;
assign rst = ~rst_n    ;

initial begin
   rst_n = 0 ;
#320
   rst_n = 1 ;
end

initial begin
   pixelclk = 0 ;
   #Pe_CLK
   forever begin
   #Pe_CLK pixelclk = ~pixelclk;
   end
end

always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		begin
			hs_reg_d0 <= 1'b0;
			vs_reg_d0 <= 1'b0;
			video_active_d0 <= 1'b0;
		end
	else
		begin
			hs_reg_d0 <= hs_reg;
			vs_reg_d0 <= vs_reg;
			video_active_d0 <= video_active;
		end
end

always@(posedge clk or posedge rst)
begin
    if(rst == 1'b1)
      h_cnt <= 12'd0;
    else if(h_cnt == H_TOTAL - 1)//horizontal counter maximum value
      h_cnt <= 12'd0;
    else
      h_cnt <= h_cnt + 12'd1;
end

//always@(posedge clk or posedge rst)
//begin
//	if(rst == 1'b1)
//		active_x <= 12'd0;
//	else if(h_cnt >= H_FP + H_SYNC + H_BP - 1)//horizontal video active
//		active_x <= h_cnt - (H_FP[11:0] + H_SYNC[11:0] + H_BP[11:0] - 12'd1);
//	else
//		active_x <= active_x;
//end

always@(posedge clk or posedge rst)
begin
      if(rst == 1'b1)
         v_cnt <= 12'd0;
      else if(h_cnt == H_FP  - 1)//horizontal sync time
         if(v_cnt == V_TOTAL - 1)//vertical counter maximum value
            v_cnt <= 12'd0;
         else
            v_cnt <= v_cnt + 12'd1;
      else
            v_cnt <= v_cnt;
end

always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		hs_reg <= 1'b0;
	else if(h_cnt == H_FP - 1)//horizontal sync begin
		hs_reg <= HS_POL;
	else if(h_cnt == H_FP + H_SYNC - 1)//horizontal sync end
		hs_reg <= ~hs_reg;
	else
		hs_reg <= hs_reg;
end

always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		h_active <= 1'b0;
	else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//horizontal active begin
		h_active <= 1'b1;
	else if(h_cnt == H_TOTAL - 1)//horizontal active end
		h_active <= 1'b0;
	else
		h_active <= h_active;
end

always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		vs_reg <= 1'd0;
	else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//vertical sync begin
		vs_reg <= HS_POL;
	else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//vertical sync end
		vs_reg <= ~vs_reg;  
	else
		vs_reg <= vs_reg;
end

always@(posedge clk or posedge rst)
begin
   if(rst == 1'b1)
      v_active <= 1'd0;
   else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//vertical active begin
      v_active <= 1'b1;
   else if((v_cnt == V_TOTAL - 1) && (h_cnt == H_FP - 1)) //vertical active end
      v_active <= 1'b0;   
   else
      v_active <= v_active;
end
////////////////import data//////////////////////
parameter 	P_TEST_NAME = "ISP_00";
wire   [23:0]    i_rgb     ;
reg    [23:0]    r_i_rgb   ;

integer             		C_CMD_FILE    ;
integer             		r_CMD_NUM     ;
integer             		r_LINE_NUM    ;
reg     	[1:(199*8)]  		r_LINE_MEM    ;
reg     	[1:(20*8)]  		r_COMMAND     ;
reg           [23:0]                      r_WDATA       ; 
reg	[8*19:1]		OPERATION	;
reg			r_SIM_END	;
time                		r_WTIME       ;

reg           [7:0]                       r_cnt         ;

assign i_rgb = (de == 1'b1) ? r_i_rgb : 24'd0 ;

initial begin
//     C_CMD_FILE	= $fopen ("D:/FPGA_Code/other/ISP_sim_single/ISP_sim_single/Data/OV5640_data_hex.txt" , "r") ;
     C_CMD_FILE	= $fopen ("D:/FPGA_CODE/Other_work/fruit/Sim/ISP_sim_single/ISP_sim_single/Data/OV5640_data_hex.txt" , "r") ;
     r_LINE_NUM 	= $fgets(r_LINE_MEM,C_CMD_FILE) ;
     r_CMD_NUM 	= $sscanf(r_LINE_MEM,"%s",r_COMMAND) ;
     r_cnt                  = 8'd0 ;
end
always @ (posedge pixelclk) begin
    if (r_SIM_END ==1'b0 && (r_CMD_NUM > 0) && (de == 1'b1)) begin
             casez (r_COMMAND)
	"data_import"	: begin
	OPERATION		= "data import ";					
	r_CMD_NUM 		= $sscanf(r_LINE_MEM,"%s %h",r_COMMAND,r_WDATA) ;
	r_i_rgb           	= r_WDATA	;
              r_LINE_NUM 	              = $fgets(r_LINE_MEM,C_CMD_FILE) ;
//	@ (posedge pixelclk);
	end
	"sim_end"		: begin
	OPERATION		= "	sim_end	"	;
	$display("-------------<< TEST COMPLETE >>------------%s	 at	%t",P_TEST_NAME, $time ) ;
	r_SIM_END = 1'b1 ;
              $fclose(C_CMD_FILE) ;
              
//	@ (posedge pixelclk)	;
	end
	default		: begin
	OPERATION	= "no OPERATION"	;
	$display("%s is a Unknown Command!",r_COMMAND);
	end
	endcase       
    end
    else if (r_SIM_END ==1'b1) begin
        if (r_cnt == 8'd30) begin
           r_SIM_END = 1'b0 ;
           C_CMD_FILE	= $fopen ("D:/FPGA_CODE/Other_work/fruit/Sim/ISP_sim_single/ISP_sim_single/Data/OV5640_data_hex.txt" , "r") ;
           r_LINE_NUM 	= $fgets(r_LINE_MEM,C_CMD_FILE) ;
           r_CMD_NUM 	= $sscanf(r_LINE_MEM,"%s",r_COMMAND) ;
        end
        else 
           r_cnt <= r_cnt + 8'd1 ;   
    end
end
//              $stop; 
//              $finish;
initial	begin
		$timeformat(-12,0,"ps",20) 		;
	OPERATION			= "reset"	;
	r_i_rgb			= 24'd0	;
              r_SIM_END			= 1'b0	;
              r_WDATA                                   = 24'd0       ;
//		# 801088 			;
//		$display("-------------<< TEST START >>------------%s	 at	%t",P_TEST_NAME, $time ) ;
//	while (r_SIM_END ==1'b0) begin
////          if (de == 1'b1) begin
//		r_LINE_NUM 	= (de == 1'b1)?($fgets(r_LINE_MEM,C_CMD_FILE)):0 	;// read 1 line from file
//              r_CMD_NUM 	= (de == 1'b1)?($sscanf(r_LINE_MEM,"%s",r_COMMAND)):0 	;// read command from line
//		if (r_CMD_NUM > 0) begin
//              casez (r_COMMAND)
//	       "data_import"	: begin
//			OPERATION		= "	data import "	;					
//			r_CMD_NUM 		= $sscanf(r_LINE_MEM,"%s %h",r_COMMAND,r_WDATA) ;
//			r_i_rgb           	= r_WDATA	;
////			@ (posedge pixelclk);
//		end
//
//		"sim_end"		: begin
//			OPERATION		= "	sim_end	"	;
//			$display("-------------<< TEST COMPLETE >>------------%s	 at	%t",P_TEST_NAME, $time ) ;
//			r_SIM_END = 1'b1 ;
////			@ (posedge pixelclk)	;        
//		end
//
//		default		: begin
//			OPERATION	= "no OPERATION"	;
//			$display("%s is a Unknown Command!",r_COMMAND);
//		end
//		endcase
//		end
////          end
//        @ (posedge pixelclk);
//	end
////# 160000 			;
//$fclose(C_CMD_FILE) ;
//$stop; 
end
////////////////////////////////////////////////
ISP ISP1(

    .pixelclk (pixelclk   ),
    .rstin    (rst_n      ),
    .i_rgb    (i_rgb      ),
    .i_hsync  (hs         ),
    .i_vsync  (vs         ),
    .i_de     (de         ),

    .red_en  (),
    .grenn_en(),
    .blue_en (),

    .VGA_rgb  (VGA_rgb   ),
    .VGA_hsync(VGA_hsync ),
    .VGA_vsync(VGA_vsync ),
    .VGA_de   (VGA_de    )
   );

endmodule