dakies/OSS_Verilog huggingface dataset:
module maxp(clk,maxp_en,memstartp,memstartzap,read_addressp,write_addressp,re,we,qp,dp,STOP,matrix2,matrix);

parameter SIZE_1=0;
parameter SIZE_2=0;
parameter SIZE_3=0;
parameter SIZE_4=0;
parameter SIZE_address_pix=0;

input clk,maxp_en;
output reg STOP;
input [SIZE_address_pix-1:0] memstartp,memstartzap;
output reg [SIZE_address_pix-1:0] read_addressp,write_addressp;
output reg re,we;
input signed [SIZE_1-1:0] qp;
output reg signed [SIZE_1-1:0] dp;
input [4:0] matrix;
input [9:0] matrix2;

reg [9:0] i;
reg [9:0] j;
reg [SIZE_1-1:0] buff;
reg [2:0] marker;
wire [9:0] i_wr,i_read;
initial i=0;
initial j=0;
initial marker=0;
always @(posedge clk)
begin
if (maxp_en==1)
    begin
    case (marker)
        0: begin read_addressp=memstartp+i_read; re=1;
                 if ((i!=0)||(j!=0))
                 begin
                 if (qp[SIZE_1-1:0]>buff[SIZE_1-1:0]) buff[SIZE_1-1:0]=qp[SIZE_1-1:0];
                 end
           end
        1: begin read_addressp=memstartp+i_read+1;
                 if ((i!=0)||(j!=0))
                 begin
                 if (qp[SIZE_1-1:0]>buff[SIZE_1-1:0]) dp[SIZE_1-1:0]=qp[SIZE_1-1:0]; else dp[SIZE_1-1:0]=buff[SIZE_1-1:0];
                 write_addressp=memstartzap+i_wr-1;
                 we=1;
                 end
           end
        2: begin read_addressp=memstartp+i_read+matrix; buff=qp; we=0; end
        3: begin read_addressp=memstartp+i_read+matrix+1;
                 if (qp[SIZE_1-1:0]>buff[SIZE_1-1:0]) buff[SIZE_1-1:0]=qp[SIZE_1-1:0];
                 if (i!=matrix-2) begin i=i+2; if (i_read==matrix2) STOP=1; end else begin i=0; j=j+1;  end
           end
        default: $display("Check case MaxPooling");
        endcase
        if (marker!=3) marker=marker+1; else marker=0;    end
else
    begin
        STOP=0;
        re=0;
        we=0;
        i=0;
        j=0;
        marker=0;
    end
end
assign i_wr=(i>>1)+j*(matrix>>1);
assign i_read=i+(matrix+matrix)*j;
endmodule
module result(clk,enable,STOP,memstartp,read_addressp,qp,re,RESULT);

parameter SIZE_1=0;
parameter SIZE_2=0;
parameter SIZE_3=0;
parameter SIZE_4=0;
parameter SIZE_address_pix=0;

input clk,enable;
output reg STOP;
input [SIZE_address_pix-1:0] memstartp;
input [SIZE_1-1:0] qp;
output reg re;
output reg [SIZE_address_pix-1:0] read_addressp;
output reg [3:0] RESULT;

reg [3:0] marker;
reg signed [SIZE_1-1:0] buff;

wire signed [SIZE_1-1:0]  p1;
always @(posedge clk)
begin
if (enable==1)
begin
re=1;
case (marker)
	0: begin read_addressp=memstartp+0; end
	1: begin read_addressp=memstartp+1; buff = 0; end
	2: begin read_addressp=memstartp+2; if (p1>=buff) begin buff=p1; RESULT=0; end end
	3: begin read_addressp=memstartp+3; if (p1>=buff) begin buff=p1; RESULT=1; end end
	4: begin read_addressp=memstartp+4; if (p1>=buff) begin buff=p1; RESULT=2; end end
	5: begin read_addressp=memstartp+5; if (p1>=buff) begin buff=p1; RESULT=3; end end
	6: begin read_addressp=memstartp+6; if (p1>=buff) begin buff=p1; RESULT=4; end end
	7: begin read_addressp=memstartp+7; if (p1>=buff) begin buff=p1; RESULT=5; end end
	8: begin read_addressp=memstartp+8; if (p1>=buff) begin buff=p1; RESULT=6; end end
	9: begin read_addressp=memstartp+9; if (p1>=buff) begin buff=p1; RESULT=7; end end
	10: begin read_addressp=memstartp+10; if (p1>=buff) begin buff=p1; RESULT=8; end end
	11: begin read_addressp=memstartp+11; if (p1>=buff) begin buff=p1; RESULT=9; end end
	12: begin read_addressp=memstartp+12; if (p1>=buff) begin buff=p1; RESULT=10; end STOP=1; end
	default: $display("Check case result");
endcase
marker=marker+1;
end
else 
begin
re=0;
marker=0;
STOP=0;
end
end

assign p1=qp[SIZE_1-1:0];
endmodule
module cam_wrp  	
(         
	input wire 					rst_n,
	input wire		[7:0]		data_cam,
	input wire					HREF_cam,
	input wire					PCLK_cam,	
	input wire					ctrl_busy,
	output wire		[15:0]	input_fifo_to_sdram,
	output reg 		[23:0]	addr_sdram,
	output reg					wr_enable
);
	reg		[15: 0]		data2fifo;	
	reg					sh_HREF_cam;
	reg 						wr_fifo;
	
	wire		[9:0]		output_rdusedw;
	
	always @( posedge PCLK_cam or negedge rst_n )
		if  ( ! rst_n )
			begin
				sh_HREF_cam	<= 1'h0;
			end			
		else
			begin
				sh_HREF_cam		<= HREF_cam;			
			end	

	always @( posedge PCLK_cam or negedge rst_n )
		if ( !rst_n )
			data2fifo	<= 16'h0;
		else
			if ( wr_fifo )
				data2fifo[7:0]	<= data_cam;
			else
				data2fifo[15:8]	<= data_cam;					

	always @( posedge PCLK_cam or negedge rst_n )
		if ( !rst_n )
			wr_fifo		<= 1'h0;
		else
			if ( HREF_cam )
				wr_fifo	<= !wr_fifo;
			else
				wr_fifo	<= 1'h0;
		
reg [8:0] sh_write;
initial sh_write=9'd0;
reg wr_enable_fifo=1'b0;

always @(posedge ctrl_busy or negedge rst_n)
	begin
		if (!rst_n)
			begin
				sh_write=9'd0;
				wr_enable<=1'b1;
				wr_enable_fifo=1'b1;
				addr_sdram=24'd0;
			end
		else
			begin
				if ((output_rdusedw>600)&&(sh_write==9'd0)) wr_enable<=1'b1;
				if ((output_rdusedw<600)&&(sh_write==9'd320)) wr_enable<=1'b0;
				if (wr_enable)
					begin
						if (sh_write!=0)
							begin
								if (addr_sdram<24'd76799)	addr_sdram=addr_sdram+1'b1;
								else	addr_sdram=24'd0;
							end
						if (sh_write<9'd320) sh_write=sh_write+1'b1;
						else 		sh_write=9'd0;
					end
			end
	end


	
fifo_1024x16 input_fifo 
(	
	.aclr					  ( !rst_n							),	
	.data					  ( data2fifo						),	
	.rdclk              ( ctrl_busy						),	
	.rdreq              ( wr_enable && (sh_write<=9'd319)			),	
	.wrclk              ( PCLK_cam						), 
	.wrreq              ( !wr_fifo && sh_HREF_cam	),	
	.q                  ( input_fifo_to_sdram			),	
	.rdempty            ( 									),
	.rdusedw            ( output_rdusedw				),				
	.wrfull             ( 									),
	.wrusedw            ( 									)
);

endmodule
module delay_rg
   #(parameter W = 16,         // ðàçðÿäíîñòü âõîäíîãî è âûõîäíîãî ñèãíàëà
     parameter D = 10)         // çàäåðæêà
   (input reset_b,
    input clk,
	input [W-1:0] data_in,     // âõîäíîé ñèãíàë
    output [W-1:0] data_out);   // âûõîäíîé ñèãíàë


	reg [W-1:0] rg [0:D-1]; 
	always @ (posedge clk, negedge reset_b) begin : delay_line
	integer i;
		if(~reset_b) begin
			for(i=0; i<D; i=i+1)
				rg[i] <= {(W){1'b0}};
		end else begin
		    rg[0] <= data_in;
			for(i=0; i<(D-1); i=i+1)
				rg[i+1] <= rg[i];
		end
	end

	assign data_out = rg[D-1];
	
endmodule
module fifo_1024x16 (
	aclr,
	data,
	rdclk,
	rdreq,
	wrclk,
	wrreq,
	q,
	rdempty,
	rdusedw,
	wrfull,
	wrusedw);

	input	  aclr;
	input	[15:0]  data;
	input	  rdclk;
	input	  rdreq;
	input	  wrclk;
	input	  wrreq;
	output	[15:0]  q;
	output	  rdempty;
	output	[11:0]  rdusedw;
	output	  wrfull;
	output	[11:0]  wrusedw;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri0	  aclr;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

	wire [15:0] sub_wire0;
	wire  sub_wire1;
	wire [11:0] sub_wire2;
	wire  sub_wire3;
	wire [11:0] sub_wire4;
	wire [15:0] q = sub_wire0[15:0];
	wire  rdempty = sub_wire1;
	wire [11:0] rdusedw = sub_wire2[11:0];
	wire  wrfull = sub_wire3;
	wire [11:0] wrusedw = sub_wire4[11:0];

	dcfifo	dcfifo_component (
				.aclr (aclr),
				.data (data),
				.rdclk (rdclk),
				.rdreq (rdreq),
				.wrclk (wrclk),
				.wrreq (wrreq),
				.q (sub_wire0),
				.rdempty (sub_wire1),
				.rdusedw (sub_wire2),
				.wrfull (sub_wire3),
				.wrusedw (sub_wire4),
				.eccstatus (),
				.rdfull (),
				.wrempty ());
	defparam
		dcfifo_component.intended_device_family = "Cyclone II",
		dcfifo_component.lpm_hint = "MAXIMIZE_SPEED=5,",
		dcfifo_component.lpm_numwords = 4096,
		dcfifo_component.lpm_showahead = "OFF",
		dcfifo_component.lpm_type = "dcfifo",
		dcfifo_component.lpm_width = 16,
		dcfifo_component.lpm_widthu = 12,
		dcfifo_component.overflow_checking = "ON",
		dcfifo_component.rdsync_delaypipe = 3,
		dcfifo_component.underflow_checking = "ON",
		dcfifo_component.use_eab = "ON",
		dcfifo_component.write_aclr_synch = "OFF",
		dcfifo_component.wrsync_delaypipe = 3;


endmodule
module camera_read(
	input wire p_clock,
	input wire vsync,
	input wire href,
	input wire [7:0] p_data,
	output reg [15:0] pixel_data =0,
	output reg pixel_valid = 0,
	output reg frame_done = 0
    );
	 
	
	reg [1:0] FSM_state = 0;
    reg pixel_half = 0;
	
	localparam WAIT_FRAME_START = 0;
	localparam ROW_CAPTURE = 1;
	
	
	always@(posedge p_clock)
	begin 
	
	case(FSM_state)
	
	WAIT_FRAME_START: begin //wait for VSYNC
	   FSM_state <= (!vsync) ? ROW_CAPTURE : WAIT_FRAME_START;
	   frame_done <= 0;
	   pixel_half <= 0;
	end
	
	ROW_CAPTURE: begin 
	   FSM_state <= vsync ? WAIT_FRAME_START : ROW_CAPTURE;
	   frame_done <= vsync ? 1 : 0;
	   pixel_valid <= (href && pixel_half) ? 1 : 0; 
	   if (href) begin
	       pixel_half <= ~ pixel_half;
	       if (pixel_half) pixel_data[7:0] <= p_data;
	       else pixel_data[15:8] <= p_data;
	   end
	end
	
	
	endcase
	end
	
endmodule
module OV7670_config
#(
    parameter CLK_FREQ = 25000000
)
(
    input wire clk,
    input wire SCCB_interface_ready,
    input wire [15:0] rom_data,
    input wire start,
    output reg [7:0] rom_addr,
    output reg done,
    output reg [7:0] SCCB_interface_addr,
    output reg [7:0] SCCB_interface_data,
    output reg SCCB_interface_start
    );
    
    initial begin
        rom_addr = 0;
        done = 0;
        SCCB_interface_addr = 0;
        SCCB_interface_data = 0;
        SCCB_interface_start = 0;
    end
    
    localparam FSM_IDLE = 0;
    localparam FSM_SEND_CMD = 1;
    localparam FSM_DONE = 2;
    localparam FSM_TIMER = 3;
    
    reg [2:0] FSM_state = FSM_IDLE;
    reg [2:0] FSM_return_state;
    reg [31:0] timer = 0; 
    
    always@(posedge clk) begin
    
        case(FSM_state)
            
            FSM_IDLE: begin 
                FSM_state <= start ? FSM_SEND_CMD : FSM_IDLE;
                rom_addr <= 1'h0;
                done <= start ? 1'h0 : done;
            end
            
            FSM_SEND_CMD: begin 
                case(rom_data)
                    16'hFFFF: begin //end of ROM
                        FSM_state <= FSM_DONE;
                    end
                    
                    16'hFFF0: begin //delay state 
                        timer <= (CLK_FREQ/100); //10 ms delay
                        FSM_state <= FSM_TIMER;
                        FSM_return_state <= FSM_SEND_CMD;
                        rom_addr <= rom_addr + 1'h1;
                    end
                    
                    default: begin //normal rom commands
                        if (SCCB_interface_ready) begin
                            FSM_state <= FSM_TIMER;
                            FSM_return_state <= FSM_SEND_CMD;
                            timer <= 1'h0; //one cycle delay gives ready chance to deassert
                            rom_addr <= rom_addr + 1'h1;
                            SCCB_interface_addr <= rom_data[15:8];
                            SCCB_interface_data <= rom_data[7:0];
                            SCCB_interface_start <= 1;
                        end
                    end
                endcase
            end
                        
            FSM_DONE: begin //signal done 
                FSM_state <= FSM_IDLE;
                done <= 1'h1;
            end
                           
                
            FSM_TIMER: begin //count down and jump to next state
                FSM_state <= (timer == 0) ? FSM_return_state : FSM_TIMER;
                timer <= (timer==0) ? 0 : ( timer - 1'h1 );
                SCCB_interface_start <= 1'h0;
            end
        endcase
    end
endmodule
module camera_configure
    #(
    parameter CLK_FREQ=25000000
    )
    (
    input wire clk,
    input wire start,
    output wire sioc,
    output wire siod,
    output wire done
    );
    
    wire [7:0] rom_addr;
    wire [15:0] rom_dout;
    wire [7:0] SCCB_addr;
    wire [7:0] SCCB_data;
    wire SCCB_start;
    wire SCCB_ready;
    wire SCCB_SIOC_oe;
    wire SCCB_SIOD_oe;
    
    assign sioc = SCCB_SIOC_oe ? 1'b0 : 1'bZ;
    assign siod = SCCB_SIOD_oe ? 1'b0 : 1'bZ;
    
    OV7670_config_rom rom1(
        .clk(clk),
        .addr(rom_addr),
        .dout(rom_dout)
        );
        
    OV7670_config #(.CLK_FREQ(CLK_FREQ)) config_1(
        .clk(clk),
        .SCCB_interface_ready(SCCB_ready),
        .rom_data(rom_dout),
        .start(start),
        .rom_addr(rom_addr),
        .done(done),
        .SCCB_interface_addr(SCCB_addr),
        .SCCB_interface_data(SCCB_data),
        .SCCB_interface_start(SCCB_start)
        );
    
    SCCB_interface #( .CLK_FREQ(CLK_FREQ)) SCCB1(
        .clk(clk),
        .start(SCCB_start),
        .address(SCCB_addr),
        .data(SCCB_data),
        .ready(SCCB_ready),
        .SIOC_oe(SCCB_SIOC_oe),
        .SIOD_oe(SCCB_SIOD_oe)
        );
    
endmodule
module vga_driver(
    input vga_clk,
    input sys_rst_n,   
    // vga interface
    output vga_hs,
    output vga_vs,
    output [11:0] vga_rgb,
    input [11:0] pixel_data,
    output [9:0] pixel_xpos,
    output [9:0] pixel_ypos
);

parameter H_SYNC = 10'd96;
parameter H_BACK = 10'd48;
parameter H_DISP = 10'd640;
parameter H_FRONT = 10'd16;
parameter H_TOTAL = 10'd800;

parameter V_SYNC = 10'd2;
parameter V_BACK = 10'd33;
parameter V_DISP = 10'd480;
parameter V_FRONT = 10'd10;
parameter V_TOTAL = 10'd525;

reg [9:0] cnt_h;
reg [9:0] cnt_v;

wire vga_en;
wire data_req;

assign vga_hs = (cnt_h <= H_SYNC - 1'b1)? 1'b0:1'b1;
assign vga_vs = (cnt_v <= V_SYNC - 1'b1)? 1'b0:1'b1;

assign vga_en = (((cnt_h >= H_SYNC + H_BACK) && (cnt_h < H_SYNC + H_BACK + H_DISP))
                &&((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK + V_DISP)))?
                1'b1:1'b0;

assign vga_rgb = vga_en? pixel_data:12'd0;

assign data_req = (((cnt_h >= H_SYNC + H_BACK -1'b1) && (cnt_h < H_SYNC + H_BACK + H_DISP-1'b1))
                &&((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK + V_DISP)))?
                1'b1:1'b0;

assign pixel_xpos = data_req ? (cnt_h-(H_SYNC + H_BACK -1'b1)) : 10'd0;
assign pixel_ypos = data_req ? (cnt_v-(V_SYNC + V_BACK -1'b1)) : 10'd0;

always @(posedge vga_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        cnt_h <= 10'd0;
    else begin
        if (cnt_h < H_TOTAL - 1'b1)
            cnt_h <= cnt_h + 1'b1;
        else
            cnt_h <= 10'd0;
    end
end

always @(posedge vga_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        cnt_v <= 10'd0;
    else if (cnt_h == H_TOTAL - 1'b1)begin
        if (cnt_v < V_TOTAL - 1'b1)
            cnt_v <= cnt_v + 1'b1;
        else
            cnt_v <= 10'd0;
    end
end

endmodule
module WireDelay # (
  parameter Delay_g = 0,
  parameter Delay_rd = 0,
  parameter ERR_INSERT = "OFF"
)
(
  inout A,
  inout B,
  input reset,
  input phy_init_done
);

  reg A_r;
  reg B_r;
  reg B_inv ;
  reg line_en;

  reg B_nonX;

  assign A = A_r;
  assign B = B_r;

  always @ (*)
  begin
    if (B === 1'bx)
      B_nonX <= $random;
    else
      B_nonX <= B;
   end
   
  always@(*)
  begin
    if((B_nonX == 'b1) || (B_nonX == 'b0))
      B_inv <= #0 ~B_nonX ;
    else
      B_inv <= #0 'bz ;
   end
   
  always @(*) begin
    if (!reset) begin
      A_r <= 1'bz;
      B_r <= 1'bz;
      line_en <= 1'b0;
    end else begin
      if (line_en) begin
	B_r <= 1'bz;
	  if ((ERR_INSERT == "ON") & (phy_init_done))
            A_r <= #Delay_rd B_inv;
	  else
            A_r <= #Delay_rd B_nonX;
      end else begin
        B_r <= #Delay_g A;
	A_r <= 1'bz;
      end
    end
  end

  always @(A or B) begin
    if (!reset) begin
      line_en <= 1'b0;
    end else if (A !== A_r) begin
      line_en <= 1'b0;
    end else if (B_r !== B) begin
      line_en <= 1'b1;
    end else begin
      line_en <= line_en;
    end
  end
endmodule
module NMS_AddrCal (refAddr, adjNumber, scoreAddr);
	input [14:0] refAddr; // 기준점
	input [3:0] adjNumber; // 인접한 8개의 점 번호
	output [14:0] scoreAddr; // Score Memory의 Input 주소
	
	assign scoreAddr =
		(adjNumber == 4'd15) ? refAddr : // 현재 Score Memory Addr
		(adjNumber == 4'd0) ? refAddr - 182 : // 기준점 
		(adjNumber == 4'd1) ? refAddr - 182 - `COLUMNS : // 1
		(adjNumber == 4'd2) ? refAddr - 182 - `COLUMNS + 1 : // 2
		(adjNumber == 4'd3) ? refAddr - 182 + 1 : // 3
		(adjNumber == 4'd4) ? refAddr - 182 + `COLUMNS + 1 : // 4
		(adjNumber == 4'd5) ? refAddr - 182 + `COLUMNS : // 5
		(adjNumber == 4'd6) ? refAddr - 182 + `COLUMNS - 1 : // 6
		(adjNumber == 4'd7) ? refAddr - 182 - 1 : // 7
		(adjNumber == 4'd8) ? refAddr - 182 - `COLUMNS - 1 : 15'bx; // 8
endmodule
module NMS_Controller (clock, nReset, refAddr, adjNumber, regAddr, readen);
	input clock;
	input nReset;
	input [14:0] refAddr; // 현재 주소
	output [3:0] adjNumber; // 인접한 8개의 점의 번호
	output [3:0] regAddr; // 레지스터 주소
	output readen; // datapath에 보낼 읽기 신호
	
	reg [3:0] adjNumber; // 8개의 점 Index
	reg [3:0] regAddr; // 레지스터 주소
	reg readen; // Datapath가 수행될 수 있도록 하는 enable 신호
	
	reg [4:0] curState, nextState; // 상태 변화
	
	// 클락이 상승할 때마다 현재 상태에서 다음상태로 변화
	always @(posedge clock or negedge nReset) begin
		if (!nReset)
			curState <= `INIT;
		else
			curState <= nextState;
	end
	
	// FSM
	always @(curState or refAddr) begin
		casex (curState)
			`INIT: begin
				if (refAddr < 15'd904) begin
					nextState = `INIT;
					readen = 1'b0;
				end
				else begin
					nextState = `S0;
					readen = 1'b0;
				end
			end
		
			`S0: begin
				nextState = `S1;
				adjNumber = `S0;
				regAddr = 4'bx;
			end
			
			`S1: begin
				nextState = `S2;
				adjNumber = `S1;
				regAddr = 4'bx;
			end
			
			`S2: begin
				nextState = `S3;
				adjNumber = `S2;
				regAddr = `S0;
			end
			
			`S3: begin
				nextState = `S4;
				adjNumber = `S3;
				regAddr = `S1;
			end
			
			`S4: begin
				nextState = `S5;
				adjNumber = `S4;				
				regAddr = `S2;
			end
			
			`S5: begin
				nextState = `S6;
				adjNumber = `S5;
				regAddr = `S3;
			end
			
			`S6: begin
				nextState = `S7;
				adjNumber = `S6;
				regAddr = `S4;
			end
			
			`S7: begin
				nextState = `S8;
				adjNumber = `S7;
				regAddr = `S5;
			end
			
			`S8: begin
				nextState = `S9;
				adjNumber = `S8;
				regAddr = `S6;
			end
			
			`S9: begin
				nextState = `S10;
				adjNumber = 4'bx;
				regAddr = `S7;
			end
			
			`S10: begin
				nextState = `S11;
				adjNumber = 4'bx;
				regAddr = `S8;
			end
			
			`S11: begin
				nextState = `S12;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S12: begin
				nextState = `S13;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S13: begin
				nextState = `S14;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S14: begin
				nextState = `S15;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S15: begin
				nextState = `S16;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S16: begin
				nextState = `S17;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S17: begin
				nextState = `S18;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S18: begin
				nextState = `S19;
				adjNumber = 4'bx;
				regAddr = 4'bx;
			end
			
			`S19: begin
				nextState = `INIT;
				adjNumber = 4'd15;
				regAddr = 4'bx;
				readen = 1'b1;
			end
		endcase
	end
endmodule
module NMS_Datapath (refScore, adjScore, refAddr, outAddr, outPixel);
	input [7:0] refScore; // 기준점 Score
	input [63:0] adjScore; // 인접한 8개의 점 Score
	input [14:0] refAddr; // 현재 주소
	output [14:0] outAddr; // 최종 Corner 주소
	output [7:0] outPixel; // 최종 Corner 데이터

	// 인접한 8개의 점과 비교하여 기준점의 Score가 모든 인접한 점보다 크면 0xff로 최종 Corner 출력
	assign outPixel = 
		(refScore == 8'd0) ? 8'bx : // Corner가 아닌 경우
		(refScore < adjScore[63:56]) ? 8'bx :
		(refScore < adjScore[55:48]) ? 8'bx :
		(refScore < adjScore[47:40]) ? 8'bx :
		(refScore < adjScore[39:32]) ? 8'bx :
		(refScore < adjScore[31:24]) ? 8'bx :
		(refScore < adjScore[23:16]) ? 8'bx :
		(refScore < adjScore[15:8]) ? 8'bx :
		(refScore < adjScore[7:0]) ? 8'bx : 8'hff;
		
	// 최종적으로 결정된 코너의 주소
	assign outAddr = (outPixel == 8'hff) ? refAddr - 182 : 15'bx;
endmodule
module FS_Top (isCorner, compare, refAddr, refPixel, adjPixel, thres, scoreValue, wren);
	input isCorner; // Corner 확인
	input [31:0] compare; // DARK, BRIGHT, SIMILAR 값
	input [14:0] refAddr; // 기준점 주소
	input [7:0] refPixel; // 기준점 데이터
	input [127:0] adjPixel; // 인접한 16개의 점 데이터
	input [7:0] thres; // 임계값
	output [7:0] scoreValue; // 점수 데이터
	output wren; // Score Memory에 쓰기 신호
	
	// 코너의 스코어를 계산하는 모듈
	FS_Datapath datapth(
		.isCorner(isCorner),
		.compare(compare),
		.refPixel(refPixel),
		.adjPixel(adjPixel),
		.thres(thres),
		.wren(wren),
		.scoreValue(scoreValue)
	);
endmodule
module FD_Controller (clock, nReset, refAddr, adjNumber, regAddr, readen);
	input clock;
	input nReset;
	output [14:0] refAddr;
	output [4:0] adjNumber;
	output [4:0] regAddr;
	output readen;
	
	reg [14:0] refAddr; // 기준점 주소
	reg [4:0] adjNumber; // 16개의 점 Index
	reg [4:0] regAddr; // 레지스터 주소
	reg readen; // Datapath가 수행될 수 있도록 하는 enable 신호
	
	reg [4:0] curState, nextState; // 상태 변화
	
	// 클락이 상승할 때마다 현재 상태에서 다음상태로 변화
	always @(posedge clock or negedge nReset) begin
		if (!nReset)
			curState <= `INIT;
		else
			curState <= nextState;
	end
	
	// FSM
	always @(curState) begin
		casex (curState)
			`INIT: begin
				nextState = `S0;
				adjNumber = 5'bx;
				regAddr = 5'bx;
				readen = 1'b0;
				
				if (refAddr == 15'd21056)
					refAddr = 15'd543;
				//else if (refAddr % 177 == 0)
				//	refAddr = refAddr + 7;
				else if (refAddr != 0)
					refAddr = refAddr + 1;
				else
					refAddr = 15'd543;
			end
		
			`S0: begin
				nextState = `S1;
				adjNumber = `S0;
				regAddr = 5'bx;
			end
			
			`S1: begin
				nextState = `S2;
				adjNumber = `S1;
				regAddr = 5'bx;
			end
			
			`S2: begin
				nextState = `S3;
				adjNumber = `S2;
				regAddr = `S0;
			end
			
			`S3: begin
				nextState = `S4;
				adjNumber = `S3;
				regAddr = `S1;
			end
			
			`S4: begin
				nextState = `S5;
				adjNumber = `S4;				
				regAddr = `S2;
			end
			
			`S5: begin
				nextState = `S6;
				adjNumber = `S5;
				regAddr = `S3;
			end
			
			`S6: begin
				nextState = `S7;
				adjNumber = `S6;
				regAddr = `S4;
			end
			
			`S7: begin
				nextState = `S8;
				adjNumber = `S7;
				regAddr = `S5;
			end
			
			`S8: begin
				nextState = `S9;
				adjNumber = `S8;
				regAddr = `S6;
			end
			
			`S9: begin
				nextState = `S10;
				adjNumber = `S9;
				regAddr = `S7;
			end

			`S10: begin
				nextState = `S11;
				adjNumber = `S10;
				regAddr = `S8;
			end
			
			`S11: begin
				nextState = `S12;
				adjNumber = `S11;
				regAddr = `S9;
			end
			
			`S12: begin
				nextState = `S13;
				adjNumber = `S12;
				regAddr = `S10;
			end
			
			`S13: begin
				nextState = `S14;
				adjNumber = `S13;
				regAddr = `S11;
			end
			
			`S14: begin
				nextState = `S15;
				adjNumber = `S14;
				regAddr = `S12;
			end
			
			`S15: begin
				nextState = `S16;
				adjNumber = `S15;
				regAddr = `S13;
			end
			
			`S16: begin
				nextState = `S17;
				adjNumber = `S16;
				regAddr = `S14;
			end
			
			`S17: begin
				nextState = `S18;
				adjNumber = 5'bx;
				regAddr = `S15;
			end
			
			`S18: begin
				nextState = `S19;
				adjNumber = 5'bx;
				regAddr = `S16;
			end
			
			`S19: begin
				nextState = `INIT;
				adjNumber = 5'bx;
				regAddr = 5'bx;
				readen = 1'b1;
			end
		endcase
	end
endmodule
module Mat_AddrCal (refAddr, adjNumber, FBAddr);
	input [14:0] refAddr; // 기준점
	input [2:0] adjNumber; // 인접한 8개의 점 번호
	output [14:0] FBAddr; // Frame Buffer의 Input 주소
	
	assign FBAddr =
		(adjNumber == 4'd0) ? refAddr - `COLUMNS : // 1
		(adjNumber == 4'd1) ? refAddr - `COLUMNS + 1 : // 2
		(adjNumber == 4'd2) ? refAddr + 1 : // 3
		(adjNumber == 4'd3) ? refAddr + `COLUMNS + 1 : // 4
		(adjNumber == 4'd4) ? refAddr + `COLUMNS : // 5
		(adjNumber == 4'd5) ? refAddr + `COLUMNS - 1 : // 6
		(adjNumber == 4'd6) ? refAddr - 1 : // 7
		(adjNumber == 4'd7) ? refAddr - `COLUMNS - 1 : 15'bx; // 8
endmodule
module NMS_Reg (clock, nReset, readen, regAddr, scoreData, refScore, adjScore);
	input clock;
	input nReset;
	input readen; // Datapath에 input으로 값을 주기 위한 신호
	input [3:0] regAddr; // 레지스터 주소
	input [7:0] scoreData; // 레지스터에 저장할 값
	output [7:0] refScore; // 기준점 Score
	output [63:0] adjScore; // 인접한 8개의 점 Score

	reg [7:0] refPoint; // 기준점 데이터를 저장
	reg [7:0] r1, r2, r3, r4, r5, r6, r7, r8; // 인접한 8개 점의 데이터를 저장
	
	// 주소로부터 저장할 레지스터를 선택하기 위한 디코더로 기준점의 데이터와, 인접한 8개의 점의 데이터를 저장한다.
	wire [8:0] decoder;
	assign decoder =
		(regAddr == 4'd0) ? 9'd1 :
		(regAddr == 4'd1) ? 9'd2 :
		(regAddr == 4'd2) ? 9'd4 :
		(regAddr == 4'd3) ? 9'd8 :
		(regAddr == 4'd4) ? 9'd16 :
		(regAddr == 4'd5) ? 9'd32 :
		(regAddr == 4'd6) ? 9'd64 :
		(regAddr == 4'd7) ? 9'd128 :
		(regAddr == 4'd8) ? 9'd256 : 9'bx;
	
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			refPoint <= 8'bx;
		else if (decoder[0])
			refPoint <= scoreData;

	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r1 <= 8'bx;
		else if (decoder[1])
			r1 <= scoreData;

	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r2 <= 8'bx;
		else if (decoder[2])
			r2 <= scoreData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r3 <= 8'bx;
		else if (decoder[3])
			r3 <= scoreData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r4 <= 8'bx;
		else if (decoder[4])
			r4 <= scoreData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r5 <= 8'bx;
		else if (decoder[5])
			r5 <= scoreData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r6 <= 8'bx;
		else if (decoder[6])
			r6 <= scoreData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r7 <= 8'bx;
		else if (decoder[7])
			r7 <= scoreData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r8 <= 8'bx;
		else if (decoder[8])
			r8 <= scoreData;
	
	// readen이 1로 셋팅 되면 기준점 데이터와, 8개의 인접한 점의 데이터를 한번에 Output으로 보낸다.
	assign refScore = (readen) ? refPoint : 8'bx; // 기준점 
	assign adjScore = (readen) ? {r1, r2, r3, r4, r5, r6, r7, r8} : 64'bx; // 8개 점
endmodule
module NMS_Testbench;
	reg clock;
	reg nReset;
	
	wire [14:0] outAddr;
	wire [7:0] outPixel;
	
	always begin
		#10 clock = ~clock;
		if (clock && (outPixel == 8'hff)) // 최종적으로 결정된 Corner의 주소와 값 출력
			$display("outAddr: %d, outPixel: %h", outAddr, outPixel);
	end
	
	// FAST-9 Alogrithm Top Module
	FAST9_Top fast9(
		.clock(clock),
		.nResetedd(nReset),
		.outAddr(outAddr),
		.outPixel(outPixel)
	);
	
	initial begin
		clock = 1'b0;
		nReset = 1'b1;
		#100 nReset = 1'b0;
		#100 nReset = 1'b1;
		
		#10000000 $finish;
	end
endmodule
module DBMEM (matReaden, dbValue);
	input matReaden;
	output [287:0] dbValue;
	
	// 36개의 실제 특징점의 평균값 데이터로 matReaden이 1로 셋되면 값을 반환
	assign dbValue =
		(matReaden == 1'b1) ? 
		{8'd95, 8'd95, 8'd95, 8'd95, 8'd0, 8'd0, 8'd0, 8'd0, 8'd95, 8'd95, 8'd95, 8'd95,
		8'd159, 8'd159, 8'd255, 8'd255, 8'd159, 8'd159, 8'd159, 8'd159, 8'd255, 8'd255,
		8'd159, 8'd159, 8'd95, 8'd95, 8'd95, 8'd95, 8'd0, 8'd0, 8'd0, 8'd0, 8'd95, 8'd95, 8'd95, 8'd95} : 288'bx;
endmodule
module NMS_Top (clock, nReset, refAddr, refPixel, scoreData, scoreAddr, outAddr, outPixel);
	input clock;
	input nReset;
	input [14:0] refAddr; // 기준점 주소
	input [7:0] refPixel; // 기준점 데이터
	input [7:0] scoreData; // Score Memory에 저장할 데이터 
	output [14:0] scoreAddr; // Score Memoery 주소
	output [14:0] outAddr; // 최종적으로 결정된 코너의 주소
	output [7:0] outPixel; // 코너 여부를 확인하여 최종적으로 결정된 기준점의 데이터

	wire [3:0] adjNumber; // 1~8개의 인접한 점 번호
	wire [3:0] regAddr; // 레지스터 주소
	wire [7:0] refScore; // 기준점 Score
	wire [63:0] adjScore; // 인접한 8개의 점 Score

	// Controller, 기준점과 인접한 8개의 주소를 얻어, 레지스터에 저장하는 과정을 제어
	NMS_Controller controller(
		.clock(clock),
		.nReset(nReset),
		.refAddr(refAddr), 
		.adjNumber(adjNumber),
		.regAddr(regAddr),
		.readen(readen)
	);
	
	// 기준점으로 부터 인접한 8개의 점을 계산
	NMS_AddrCal addrCal(
		.refAddr(refAddr),
		.adjNumber(adjNumber),
		.scoreAddr(scoreAddr)
	);

	// 기준점과 인접한 8개의 점을 저장할 레지스터 파일
	NMS_Reg nms_reg(
		.clock(clock),
		.nReset(nReset),
		.readen(readen),
		.regAddr(regAddr),
		.scoreData(scoreData),
		.refScore(refScore),
		.adjScore(adjScore)
	);
	
	// 레지스터에 저장된 기준점과 인접한 8개의 점의 데이터를 이용하여 최종적으로 코너를 결정
	NMS_Datapath datapath(
		.refScore(refScore),
		.adjScore(adjScore),
		.refAddr(refAddr),
		.outAddr(outAddr),
		.outPixel(outPixel)
	);
endmodule
module SRAM (
	address,
	clock,
	data,
	wren,
	q);

	input	[14:0]  address;
	input	  clock;
	input	[7:0]  data;
	input	  wren;
	output	[7:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri1	  clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

endmodule
module FS_ScoreMem (
	address,
	clock,
	data,
	wren,
	q);

	input	[14:0]  address;
	input	  clock;
	input	[7:0]  data;
	input	  wren;
	output	[7:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri1	  clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

	wire [7:0] sub_wire0;
	wire [7:0] q = sub_wire0[7:0];

	altsyncram	altsyncram_component (
				.address_a (address),
				.clock0 (clock),
				.data_a (data),
				.wren_a (wren),
				.q_a (sub_wire0),
				.aclr0 (1'b0),
				.aclr1 (1'b0),
				.address_b (1'b1),
				.addressstall_a (1'b0),
				.addressstall_b (1'b0),
				.byteena_a (1'b1),
				.byteena_b (1'b1),
				.clock1 (1'b1),
				.clocken0 (1'b1),
				.clocken1 (1'b1),
				.clocken2 (1'b1),
				.clocken3 (1'b1),
				.data_b (1'b1),
				.eccstatus (),
				.q_b (),
				.rden_a (1'b1),
				.rden_b (1'b1),
				.wren_b (1'b0));
	defparam
		altsyncram_component.clock_enable_input_a = "BYPASS",
		altsyncram_component.clock_enable_output_a = "BYPASS",
		altsyncram_component.intended_device_family = "Cyclone IV E",
		altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
		altsyncram_component.lpm_type = "altsyncram",
		altsyncram_component.numwords_a = 21600,
		altsyncram_component.operation_mode = "SINGLE_PORT",
		altsyncram_component.outdata_aclr_a = "NONE",
		altsyncram_component.outdata_reg_a = "CLOCK0",
		altsyncram_component.power_up_uninitialized = "FALSE",
		altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
		altsyncram_component.widthad_a = 15,
		altsyncram_component.width_a = 8,
		altsyncram_component.width_byteena_a = 1;


endmodule
module Mat_Controller (clock, nReset, refAddr, adjNumber, regAddr, matReaden);
	input clock;
	input nReset;
	input [14:0] refAddr; // 기준점
	output [2:0] adjNumber; // 인접한 점 번호
	output [2:0] regAddr; // 레지스터 주소
	output matReaden;
	
	reg [2:0] adjNumber; // 8개의 점 Index
	reg [2:0] regAddr; // 레지스터 주소
	reg matReaden; // Datapath가 수행될 수 있도록 하는 enable 신호
	
	reg [3:0] curState, nextState; // 상태 변화
	
	// Clock이 상승할 때마다 현재 상태에서 다음상태로 변화
	always @(posedge clock or negedge nReset) begin
		if (!nReset)
			curState <= `INIT;
		else
			curState <= nextState;
	end
	
	// FSM
	always @(curState or refAddr) begin
		casex (curState)
			`INIT: begin
				if (refAddr)
					nextState = `S0;
					
				adjNumber = 3'bx;
				regAddr = 3'bx;
				matReaden = 1'b0;
			end
		
			`S0: begin
				nextState = `S1;
				adjNumber = 3'd0;
				regAddr = 3'bx;
			end
			
			`S1: begin
				nextState = `S2;
				adjNumber = 3'd1;
				regAddr = 3'bx;
			end
			
			`S2: begin
				nextState = `S3;
				adjNumber = 3'd2;
				regAddr = 3'd0;
			end
			
			`S3: begin
				nextState = `S4;
				adjNumber = 3'd3;
				regAddr = 3'd1;
			end
			
			`S4: begin
				nextState = `S5;
				adjNumber = 3'd4;				
				regAddr = 3'd2;
			end
			
			`S5: begin
				nextState = `S6;
				adjNumber = 3'd5;
				regAddr = 3'd3;
			end
			
			`S6: begin
				nextState = `S7;
				adjNumber = 3'd6;
				regAddr = 3'd4;
			end
			
			`S7: begin
				nextState = `S8;
				adjNumber = 3'd7;
				regAddr = 3'd5;
			end
			
			`S8: begin
				nextState = `S9;
				adjNumber = 3'dx;
				regAddr = 3'd6;
			end
			
			`S9: begin
				nextState = `S10;
				adjNumber = 3'dx;
				regAddr = 3'd7;
			end
			
			`S10: begin
				nextState = `INIT;
				adjNumber = 3'bx;
				regAddr = 3'bx;
				matReaden = 1'b1;
			end
		endcase
	end
endmodule
module SRAM (
	address,
	clock,
	data,
	wren,
	q);

	input	[14:0]  address;
	input	  clock;
	input	[7:0]  data;
	input	  wren;
	output	[7:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri1	  clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

	wire [7:0] sub_wire0;
	wire [7:0] q = sub_wire0[7:0];

	altsyncram	altsyncram_component (
				.address_a (address),
				.clock0 (clock),
				.data_a (data),
				.wren_a (wren),
				.q_a (sub_wire0),
				.aclr0 (1'b0),
				.aclr1 (1'b0),
				.address_b (1'b1),
				.addressstall_a (1'b0),
				.addressstall_b (1'b0),
				.byteena_a (1'b1),
				.byteena_b (1'b1),
				.clock1 (1'b1),
				.clocken0 (1'b1),
				.clocken1 (1'b1),
				.clocken2 (1'b1),
				.clocken3 (1'b1),
				.data_b (1'b1),
				.eccstatus (),
				.q_b (),
				.rden_a (1'b1),
				.rden_b (1'b1),
				.wren_b (1'b0));
	defparam
		altsyncram_component.clock_enable_input_a = "BYPASS",
		altsyncram_component.clock_enable_output_a = "BYPASS",
		altsyncram_component.init_file = "untitled.mif",
		altsyncram_component.intended_device_family = "Cyclone IV E",
		altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
		altsyncram_component.lpm_type = "altsyncram",
		altsyncram_component.numwords_a = 21600,
		altsyncram_component.operation_mode = "SINGLE_PORT",
		altsyncram_component.outdata_aclr_a = "NONE",
		altsyncram_component.outdata_reg_a = "CLOCK0",
		altsyncram_component.power_up_uninitialized = "FALSE",
		altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
		altsyncram_component.widthad_a = 15,
		altsyncram_component.width_a = 8,
		altsyncram_component.width_byteena_a = 1;


endmodule
module Addr_Reg (refAddr, posAddr, posReaden, position, isMatching);
	input [14:0] refAddr; // 특징점 주소
	input [3:0] posAddr; // 레지스터 주소
	input posReaden; // 매칭 여부
	output [239:0] position; // 유효 특징점 주소
	output isMatching; // 매칭 여부

	reg [14:0] r1, r2, r3, r4, r5, r6, r7, r8, r9;
	reg [14:0] r10, r11, r12, r13, r14, r15, r16;
	
	// 주소로부터 저장할 레지스터를 선택하기 위한 인접한 8개의 점의 데이터를 저장한다.
	wire [15:0] decoder;
	assign decoder =
		(posAddr == 4'd0) ? 16'd1 :
		(posAddr == 4'd1) ? 16'd2 :
		(posAddr == 4'd2) ? 16'd4 :
		(posAddr == 4'd3) ? 16'd8 :
		(posAddr == 4'd4) ? 16'd16 :
		(posAddr == 4'd5) ? 16'd32 :
		(posAddr == 4'd6) ? 16'd64 :
		(posAddr == 4'd7) ? 16'd128 :
		(posAddr == 4'd8) ? 16'd256 :
		(posAddr == 4'd9) ? 16'd512 :
		(posAddr == 4'd10) ? 16'd1024 :
		(posAddr == 4'd11) ? 16'd2048 :
		(posAddr == 4'd12) ? 16'd4096 :
		(posAddr == 4'd13) ? 16'd8192 :
		(posAddr == 4'd14) ? 16'd16384 :
		(posAddr == 4'd15) ? 16'd32768 : 4'bx;
	
	// 레지스터 저장
	always @(posAddr)
	if (decoder[0])
		r1 <= refAddr;
		
	always @(posAddr)
	if (decoder[1])
		r2 <= refAddr;
	
	always @(posAddr)
	if (decoder[2])
		r3 <= refAddr;
	
	always @(posAddr)
	if (decoder[3])
		r4 <= refAddr;
	
	always @(posAddr)
	if (decoder[4])
		r5 <= refAddr;
	
	always @(posAddr)
	if (decoder[5])
		r6 <= refAddr;
	
	always @(posAddr)
	if (decoder[6])
		r7 <= refAddr;
	
	always @(posAddr)
	if (decoder[7])
		r8 <= refAddr;
	
	always @(posAddr)
	if (decoder[8])
		r9 <= refAddr;
	
	always @(posAddr)
	if (decoder[9])
		r10 <= refAddr;
	
	always @(posAddr)
	if (decoder[10])
		r11 <= refAddr;
	
	always @(posAddr)
	if (decoder[11])
		r12 <= refAddr;
	
	always @(posAddr)
	if (decoder[12])
		r13 <= refAddr;
	
	always @(posAddr)
	if (decoder[13])
		r14 <= refAddr;
	
	always @(posAddr)
	if (decoder[14])
		r15 <= refAddr;
	
	always @(posAddr)
	if (decoder[15])
		r16 <= refAddr;
		
	// 저장된 유효 특징점의 모든 주소를 반환
	assign position = 
		(posReaden == 1'b1) ? {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16} : 240'bx;
	
	// 매칭 여부를 반환
	assign isMatching = (posReaden == 1'b1) ? 1'b1 : 1'b0;
endmodule
module Mat_Reg (clock, nReset, matReaden, regAddr, FBData, adjFBPixel);
	input clock;
	input nReset;
	input matReaden; // Datapath에 input으로 값을 주기 위한 신호
	input [2:0] regAddr; // 레지스터 주소
	input [7:0] FBData; // 레지스터에 저장할 값
	output [63:0] adjFBPixel; // 인접한 8개의 점의 픽셀 데이터

	reg [7:0] r1, r2, r3, r4, r5, r6, r7, r8; // 인접한 8개 점의 데이터를 저장
	
	// 주소로부터 저장할 레지스터를 선택하기 위한 디코더로 인접한 8개의 점의 데이터를 저장한다.
	wire [7:0] decoder;
	assign decoder =
		(regAddr == 4'd0) ? 9'd1 :
		(regAddr == 4'd1) ? 9'd2 :
		(regAddr == 4'd2) ? 9'd4 :
		(regAddr == 4'd3) ? 9'd8 :
		(regAddr == 4'd4) ? 9'd16 :
		(regAddr == 4'd5) ? 9'd32 :
		(regAddr == 4'd6) ? 9'd64 :
		(regAddr == 4'd7) ? 9'd128 : 8'bx;
	
	// 레지스터 저장
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r1 <= 8'bx;
		else if (decoder[0])
			r1 <= FBData;

	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r2 <= 8'bx;
		else if (decoder[1])
			r2 <= FBData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r3 <= 8'bx;
		else if (decoder[2])
			r3 <= FBData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r4 <= 8'bx;
		else if (decoder[3])
			r4 <= FBData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r5 <= 8'bx;
		else if (decoder[4])
			r5 <= FBData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r6 <= 8'bx;
		else if (decoder[5])
			r6 <= FBData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r7 <= 8'bx;
		else if (decoder[6])
			r7 <= FBData;
			
	always @ (posedge clock or negedge nReset)
		if (!nReset)
			r8 <= 8'bx;
		else if (decoder[7])
			r8 <= FBData;
	
	// matReaden이 1로 셋팅 되면 8개의 인접한 점의 데이터를 한번에 Output으로 보낸다.
	assign adjFBPixel = (matReaden) ? {r1, r2, r3, r4, r5, r6, r7, r8} : 64'bx; // 8개 점
endmodule
module FD_Testbench;
	reg clock;
	reg nReset;
	
	wire isCorner; // 코너 확인
	wire [14:0] refAddr; // 기준점 주소
	wire [7:0] refPixel; // 기준점 데이터
	wire [127:0] adjPixel; // 인접한 16개의 점 데이터
	wire [7:0] thres; // 임계값
	wire [31:0] compare;
	
	always begin
		#10 clock = ~clock;
		if (clock && isCorner) // 코너로 확인된 특징점인 경우에 출력
			$display($time, " isCorner: %d, refAddr: %d, refPixel: %h", isCorner, refAddr - 1, refPixel);
	end
	
	// Feature Detection Top Module
	FD_Top fd(
		.clock(clock), 
		.nReset(nReset),
		.isCorner(isCorner),
		.refAddr(refAddr),
		.refPixel(refPixel),
		.adjPixel(adjPixel),
		.thres(thres),
		.compare(compare)
	);
	
	initial begin
		clock = 1'b0;
		nReset = 1'b1;
		#100 nReset = 1'b0;
		#100 nReset = 1'b1;
		
		#10000000 $finish;
	end
endmodule
module FS_ScoreMem (
	address,
	clock,
	data,
	wren,
	q);

	input	[14:0]  address;
	input	  clock;
	input	[7:0]  data;
	input	  wren;
	output	[7:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri1	  clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

endmodule
module Buffer (
	address,
	clock,
	data,
	wren,
	q);

	input	[14:0]  address;
	input	  clock;
	input	[7:0]  data;
	input	  wren;
	output	[7:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri1	  clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

	wire [7:0] sub_wire0;
	wire [7:0] q = sub_wire0[7:0];

	altsyncram	altsyncram_component (
				.address_a (address),
				.clock0 (clock),
				.data_a (data),
				.wren_a (wren),
				.q_a (sub_wire0),
				.aclr0 (1'b0),
				.aclr1 (1'b0),
				.address_b (1'b1),
				.addressstall_a (1'b0),
				.addressstall_b (1'b0),
				.byteena_a (1'b1),
				.byteena_b (1'b1),
				.clock1 (1'b1),
				.clocken0 (1'b1),
				.clocken1 (1'b1),
				.clocken2 (1'b1),
				.clocken3 (1'b1),
				.data_b (1'b1),
				.eccstatus (),
				.q_b (),
				.rden_a (1'b1),
				.rden_b (1'b1),
				.wren_b (1'b0));
	defparam
		altsyncram_component.clock_enable_input_a = "BYPASS",
		altsyncram_component.clock_enable_output_a = "BYPASS",
		altsyncram_component.init_file = "untitled.mif",
		altsyncram_component.intended_device_family = "Cyclone IV E",
		altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
		altsyncram_component.lpm_type = "altsyncram",
		altsyncram_component.numwords_a = 21600,
		altsyncram_component.operation_mode = "SINGLE_PORT",
		altsyncram_component.outdata_aclr_a = "NONE",
		altsyncram_component.outdata_reg_a = "CLOCK0",
		altsyncram_component.power_up_uninitialized = "FALSE",
		altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
		altsyncram_component.widthad_a = 15,
		altsyncram_component.width_a = 8,
		altsyncram_component.width_byteena_a = 1;


endmodule
module Mat_Top (clock, nReset, refAddr, isFeature, position, isMatching);
	input clock;
	input nReset;
	input [14:0] refAddr; // 기준점
	input [7:0] isFeature; // 특징점 확인
	output [239:0] position; // 매칭된 유효 특징점 주소
	output isMatching; // 매칭 결과
	
	wire [2:0] adjNumber; // 8개의 인접한 점
	wire [2:0] regAddr; // 레지스터 주소
	wire [14:0] FBAddr; // Frame Buffer 주소
	wire [7:0] FBData; // Frame Buffer Output 데이터
	wire [63:0] adjFBPixel; // 인접한 8개의 점 데이터
	wire [287:0] dbValue; // DB 데이터
	wire [3:0] posAddr; // 레지스터 주소
	wire matPoint; // 매칭 여부

	// Controller, 특징점과 인접한 8개의 주소를 얻어, 레지스터에 저장하는 과정을 제어
	Mat_Controller controller(
		.clock(clock),
		.nReset(nReset),
		.refAddr(refAddr),
		.adjNumber(adjNumber),
		.regAddr(regAddr),
		.matReaden(matReaden)
	);
	
	// 기준점으로부터 인접한 8개의 점의 주소를 계산
	Mat_AddrCal addrCal(
		.refAddr(refAddr),
		.adjNumber(adjNumber),
		.FBAddr(FBAddr)
	);
	
	// 인접한 8개의 픽셀 값을 저장
	Mat_Reg mat_reg(
		.clock(clock),
		.nReset(nReset),
		.matReaden(matReaden),
		.regAddr(regAddr),
		.FBData(FBData),
		.adjFBPixel(adjFBPixel)
	);
	
	// DB의 데이터와 레지스터의 저장된 특징점 주변의 평균값의 1:N 비교를 통해 매칭여부 확인
	Mat_Datapath datapath(
		.adjFBPixel(adjFBPixel),
		.dbValue(dbValue),
		.matPoint(matPoint)
	);
	
	// 실제 이미지의 특징점의 평균값이 저장
	DBMEM dbmem(
		.matReaden(matReaden),
		.dbValue(dbValue)
	);

	// 최종적으로 매칭된 특징점의 주소를 저장 
	Addr_Reg addr_reg(
		.refAddr(refAddr),
		.posAddr(posAddr),
		.posReaden(posReaden),
		.position(position),
		.isMatching(isMatching)
	);
	
	// 매칭된 특징점의 개수를 센다.
	Mat_Counter counter(
		.clock(clock),
		.nReset(nReset),
		.matPoint(matPoint),
		.isFeature(isFeature),
		.posAddr(posAddr),
		.posReaden(posReaden)
	);
	
	// Freme Buffer
	Buffer buffer(
		.clock(clock),
		.address(FBAddr),
		.data(8'bx),
		.wren(1'b0),
		.q(FBData)
	);
endmodule
module Mat_Datapath (adjFBPixel, dbValue, matPoint);
	input [63:0] adjFBPixel; // 인접한 8개의 점 데이터
	input [287:0] dbValue; // DB 데이터
	output matPoint; // 매칭 여부

	wire [7:0] refAvg; // 특징점 주변의 평균값
	wire [7:0] threshold; // 임계값
	
	// 임의 임계값
	assign threshold = 8'd30;
	
	// 특징점 평균값 계산
	assign refAvg = 
		(adjFBPixel[7:0] +
		adjFBPixel[15:8] +
		adjFBPixel[23:16] +
		adjFBPixel[31:24] +
		adjFBPixel[39:32] +
		adjFBPixel[47:40] +
		adjFBPixel[55:48] +
		adjFBPixel[63:56]) / 8;
	
	// 각 뺄셈 결과가 threshold 이하 값이 나올 경우 해당 특징점은 유효 특징점으로 판단
	assign matPoint =
		(dbValue[7:0] - refAvg < threshold) ? 1'b1 :
		(dbValue[15:8] - refAvg < threshold) ? 1'b1 :
		(dbValue[23:16] - refAvg < threshold) ? 1'b1 :
		(dbValue[31:24] - refAvg < threshold) ? 1'b1 :
		(dbValue[39:32] - refAvg < threshold) ? 1'b1 :
		(dbValue[47:40] - refAvg < threshold) ? 1'b1 :
		(dbValue[55:48] - refAvg < threshold) ? 1'b1 :
		(dbValue[63:56] - refAvg < threshold) ? 1'b1 :
		(dbValue[71:64] - refAvg < threshold) ? 1'b1 :
		(dbValue[79:72] - refAvg < threshold) ? 1'b1 :
		(dbValue[87:80] - refAvg < threshold) ? 1'b1 :
		(dbValue[95:88] - refAvg < threshold) ? 1'b1 :
		(dbValue[103:96] - refAvg < threshold) ? 1'b1 :
		(dbValue[111:104] - refAvg < threshold) ? 1'b1 :
		(dbValue[119:112] - refAvg < threshold) ? 1'b1 :
		(dbValue[127:120] - refAvg < threshold) ? 1'b1 :
		(dbValue[135:128] - refAvg < threshold) ? 1'b1 :
		(dbValue[143:136] - refAvg < threshold) ? 1'b1 :
		(dbValue[151:144] - refAvg < threshold) ? 1'b1 :
		(dbValue[159:152] - refAvg < threshold) ? 1'b1 :
		(dbValue[167:160] - refAvg < threshold) ? 1'b1 :
		(dbValue[175:168] - refAvg < threshold) ? 1'b1 :
		(dbValue[183:176] - refAvg < threshold) ? 1'b1 :
		(dbValue[191:184] - refAvg < threshold) ? 1'b1 :
		(dbValue[199:192] - refAvg < threshold) ? 1'b1 :
		(dbValue[207:200] - refAvg < threshold) ? 1'b1 :
		(dbValue[215:208] - refAvg < threshold) ? 1'b1 :
		(dbValue[223:216] - refAvg < threshold) ? 1'b1 :
		(dbValue[231:224] - refAvg < threshold) ? 1'b1 :
		(dbValue[239:232] - refAvg < threshold) ? 1'b1 :
		(dbValue[247:240] - refAvg < threshold) ? 1'b1 :
		(dbValue[255:248] - refAvg < threshold) ? 1'b1 :
		(dbValue[263:256] - refAvg < threshold) ? 1'b1 :
		(dbValue[271:264] - refAvg < threshold) ? 1'b1 :
		(dbValue[279:272] - refAvg < threshold) ? 1'b1 :
		(dbValue[287:280] - refAvg < threshold) ? 1'b1 : 1'b0;
endmodule
module FD_AddrCal (refAddr, adjNumber, sramAddr);
	input [14:0] refAddr; // 기준점
	input [4:0] adjNumber; // 인접한 16개의 점
	output [14:0] sramAddr; // SRAM의 Input 주소
	
	assign sramAddr =
		(adjNumber == 5'd0) ? refAddr : // 기준점 
		(adjNumber == 5'd1) ? refAddr - (3 * `COLUMNS) : // 1
		(adjNumber == 5'd2) ? refAddr - (3 * `COLUMNS) + 1 : // 2
		(adjNumber == 5'd3) ? refAddr - (2 * `COLUMNS) + 2 : // 3
		(adjNumber == 5'd4) ? refAddr - (1 * `COLUMNS) + 3 : // 4
		(adjNumber == 5'd5) ? refAddr + 3 : // 5
		(adjNumber == 5'd6) ? refAddr + (1 * `COLUMNS) + 3 : // 6
		(adjNumber == 5'd7) ? refAddr + (2 * `COLUMNS) + 2 : // 7
		(adjNumber == 5'd8) ? refAddr + (3 * `COLUMNS) + 1 : // 8
		(adjNumber == 5'd9) ? refAddr + (3 * `COLUMNS) : // 9
		(adjNumber == 5'd10) ? refAddr + (3 * `COLUMNS) - 1 : // 10
		(adjNumber == 5'd11) ? refAddr + (2 * `COLUMNS) - 2 : // 11
		(adjNumber == 5'd12) ? refAddr + (1 * `COLUMNS) - 3 : // 12
		(adjNumber == 5'd13) ? refAddr - 3 : // 13
		(adjNumber == 5'd14) ? refAddr - (1 * `COLUMNS) - 3 : // 14
		(adjNumber == 5'd15) ? refAddr - (2 * `COLUMNS) - 2 : // 15
		(adjNumber == 5'd16) ? refAddr - (3 * `COLUMNS) - 1 : 15'bx; // 16
endmodule
module Mat_Testbench;
	reg clock;
	reg nReset;
	
	wire [239:0] position;
	wire isMatching;
	
	always begin
		#10 clock = ~clock;
	end
	
	// FAST-9 and SAD Matching Top Module
	Accelerator_Top accelerator(
		.clock(clock),
		.nReset(nReset),
		.position(position),
		.isMatching(isMatching)
	);

	initial begin
		clock = 1'b0;
		nReset = 1'b1;
		#100 nReset = 1'b0;
		#100 nReset = 1'b1;
		
		#10000000 $finish;
	end
endmodule
module Mat_Counter (clock, nReset, matPoint, isFeature, posAddr, posReaden);
	input clock;
	input nReset;
	input matPoint; // Datapath에서 유효 특징점 여부
	input [7:0] isFeature; // 특징점 확인 변수
	output [3:0] posAddr; // 레지스터 주소
	output posReaden; // 매칭 여부
	
	reg [3:0] posAddr;
	reg posReaden;
	reg [3:0] curState, nextState; // 상태 변화
	
	// Clock이 상승할 때마다 현재 상태에서 다음상태로 변화
	always @(posedge clock or negedge nReset) begin
		if (!nReset)
			curState <= `INIT;
		else
			curState <= nextState;
	end
	
	// FSM
	always @(curState or matPoint or isFeature) begin
		casex (curState)
			`INIT: begin
				if (matPoint && isFeature) begin
					nextState = `S1;
					posAddr = 4'd0;
					posReaden = 1'b0;
				end
			end
			
			`S1: begin
				if (matPoint) begin
					nextState = `S2;
					posAddr = 4'd1;
					posReaden = 1'b0;
				end
			end
			
			`S2: begin
				if (matPoint) begin
					nextState = `S3;
					posAddr = 4'd2;
					posReaden = 1'b0;
				end
			end
			
			`S3: begin
				if (matPoint) begin
					nextState = `S4;
					posAddr = 4'd3;
					posReaden = 1'b0;
				end
			end
			
			`S4: begin
				if (matPoint) begin
					nextState = `S5;
					posAddr = 4'd4;
					posReaden = 1'b0;
				end
			end
			
			`S5: begin
				if (matPoint) begin
					nextState = `S6;
					posAddr = 4'd5;
					posReaden = 1'b0;
				end
			end
			
			`S6: begin
				if (matPoint) begin
					nextState = `S7;
					posAddr = 4'd6;
					posReaden = 1'b0;
				end
			end
			
			`S7: begin
				if (matPoint) begin
					nextState = `S8;
					posAddr = 4'd7;
					posReaden = 1'b0;
				end
			end
			
			`S8: begin
				if (matPoint) begin
					nextState = `S9;
					posAddr = 4'd8;
					posReaden = 1'b0;
				end
			end
			
			`S9: begin
				if (matPoint) begin
					nextState = `S10;
					posAddr = 4'd9;
					posReaden = 1'b0;
				end
			end
			
			`S10: begin
				if (matPoint) begin
					nextState = `S11;
					posAddr = 4'd10;
					posReaden = 1'b0;
				end
			end
			
			`S11: begin
				if (matPoint) begin
					nextState = `S12;
					posAddr = 4'd11;
					posReaden = 1'b0;
				end
			end
			
			`S12: begin
				if (matPoint) begin
					nextState = `S13;
					posAddr = 4'd12;
					posReaden = 1'b0;
				end
			end
			
			`S13: begin
				if (matPoint) begin
					nextState = `S14;
					posAddr = 4'd13;
					posReaden = 1'b0;
				end
			end
			
			`S14: begin
				if (matPoint) begin
					nextState = `S15;
					posAddr = 4'd14;
					posReaden = 1'b0;
				end
			end
			
			`S15: begin
				if (matPoint) begin
					nextState = `INIT;
					posAddr = 4'd15;
					posReaden = 1'b1;
				end
			end
		endcase
	end
endmodule