dakies/OSS_Verilog huggingface dataset:
module video_mnist_color
		#(
			parameter	DATA_WIDTH      = 8,
			parameter	TUSER_WIDTH     = 1,
			parameter	TDATA_WIDTH     = 4*DATA_WIDTH,
			parameter	TNUMBER_WIDTH   = 4,
			parameter	TCOUNT_WIDTH    = 4,
		
			parameter	WB_ADR_WIDTH    = 8,
			parameter	WB_DAT_WIDTH    = 32,
			parameter	WB_SEL_WIDTH    = (WB_DAT_WIDTH / 8),
			parameter	INIT_PARAM_MODE = 2'b10,
			parameter	INIT_PARAM_TH   = 7
		)
		(
			input	wire							aresetn,
			input	wire							aclk,
			
			input	wire	[TUSER_WIDTH-1:0]		s_axi4s_tuser,
			input	wire							s_axi4s_tlast,
			input	wire	[TNUMBER_WIDTH-1:0]		s_axi4s_tnumber,
			input	wire	[TCOUNT_WIDTH-1:0]		s_axi4s_tcount,
			input	wire	[TDATA_WIDTH-1:0]		s_axi4s_tdata,
			input	wire	[0:0]					s_axi4s_tbinary,
			input	wire							s_axi4s_tvalid,
			output	wire							s_axi4s_tready,
			
			output	wire	[TUSER_WIDTH-1:0]		m_axi4s_tuser,
			output	wire							m_axi4s_tlast,
			output	wire	[TDATA_WIDTH-1:0]		m_axi4s_tdata,
			output	wire							m_axi4s_tvalid,
			input	wire							m_axi4s_tready,
			
			input	wire							s_wb_rst_i,
			input	wire							s_wb_clk_i,
			input	wire	[WB_ADR_WIDTH-1:0]		s_wb_adr_i,
			input	wire	[WB_DAT_WIDTH-1:0]		s_wb_dat_i,
			output	wire	[WB_DAT_WIDTH-1:0]		s_wb_dat_o,
			input	wire							s_wb_we_i,
			input	wire	[WB_SEL_WIDTH-1:0]		s_wb_sel_i,
			input	wire							s_wb_stb_i,
			output	wire							s_wb_ack_o
		);
	
	
	reg		[1:0]					reg_param_mode;
	reg		[TCOUNT_WIDTH-1:0]		reg_param_th;
	always @(posedge s_wb_clk_i) begin
		if ( s_wb_rst_i ) begin
			reg_param_mode <= INIT_PARAM_MODE;
			reg_param_th   <= INIT_PARAM_TH;
		end
		else begin
			if ( s_wb_stb_i && s_wb_we_i ) begin
				case ( s_wb_adr_i )
				0:	reg_param_mode <= s_wb_dat_i;
				1:	reg_param_th   <= s_wb_dat_i;
				endcase
			end
		end
	end
	
	assign s_wb_dat_o = (s_wb_adr_i == 0) ? reg_param_mode :
	                    (s_wb_adr_i == 1) ? reg_param_th   :
	                    0;
	assign s_wb_ack_o = s_wb_stb_i;
	
	
	(* ASYNC_REG="true" *)	reg			[1:0]				ff0_param_mode, ff1_param_mode;
	(* ASYNC_REG="true" *)	reg			[TCOUNT_WIDTH-1:0]	ff0_param_th,   ff1_param_th;
	always @(posedge aclk) begin
		ff0_param_mode <= reg_param_mode;
		ff1_param_mode <= ff0_param_mode;
		
		ff0_param_th   <= reg_param_th;
		ff1_param_th   <= ff0_param_th;
	end
	
	
	video_mnist_color_core
			#(
				.TUSER_WIDTH		(TUSER_WIDTH),
				.TDATA_WIDTH		(TDATA_WIDTH),
				.TNUMBER_WIDTH		(TNUMBER_WIDTH),
				.TCOUNT_WIDTH		(TCOUNT_WIDTH)
			)
		i_video_mnist_color_core
			(
				.aresetn			(aresetn),
				.aclk				(aclk),
				
				.param_mode			(ff1_param_mode),
				.param_th			(ff1_param_th),
				
				.s_axi4s_tuser		(s_axi4s_tuser),
				.s_axi4s_tlast		(s_axi4s_tlast),
				.s_axi4s_tnumber	(s_axi4s_tnumber),
				.s_axi4s_tcount		(s_axi4s_tcount),
				.s_axi4s_tdata		(s_axi4s_tdata),
				.s_axi4s_tbinary	(s_axi4s_tbinary),
				.s_axi4s_tvalid		(s_axi4s_tvalid),
				.s_axi4s_tready		(s_axi4s_tready),
				
				.m_axi4s_tuser		(m_axi4s_tuser),
				.m_axi4s_tlast		(m_axi4s_tlast),
				.m_axi4s_tdata		(m_axi4s_tdata),
				.m_axi4s_tvalid		(m_axi4s_tvalid),
				.m_axi4s_tready		(m_axi4s_tready)
			);
	
	
	
endmodule
module video_dnn_max_count
		#(
			parameter	NUM_CALSS     = 10,
			parameter	CHANNEL_WIDTH = 8,
			
			parameter	TUSER_WIDTH   = 1,
			parameter	TDATA_WIDTH   = CHANNEL_WIDTH*NUM_CALSS,
			parameter	TNUMBER_WIDTH = 4,
			parameter	TCOUNT_WIDTH  = 4
		)
		(
			input	wire							aresetn,
			input	wire							aclk,
			
			input	wire	[TUSER_WIDTH-1:0]		s_axi4s_tuser,
			input	wire							s_axi4s_tlast,
			input	wire	[TDATA_WIDTH-1:0]		s_axi4s_tdata,
			input	wire							s_axi4s_tvalid,
			output	wire							s_axi4s_tready,
			
			output	wire	[TUSER_WIDTH-1:0]		m_axi4s_tuser,
			output	wire							m_axi4s_tlast,
			output	wire	[TNUMBER_WIDTH-1:0]		m_axi4s_tnumber,
			output	wire	[TCOUNT_WIDTH-1:0]		m_axi4s_tcount,
			output	wire	[TDATA_WIDTH-1:0]		m_axi4s_tdata,
			output	wire							m_axi4s_tvalid,
			input	wire							m_axi4s_tready
		);
	
	
	wire									cke;
	
	
	// counting
	integer									i, j;
	integer									sum;
	
	reg										counting_tlast;
	reg		[TUSER_WIDTH-1:0]				counting_tuser;
	reg		[TDATA_WIDTH-1:0]				counting_tdata;
	reg		[TCOUNT_WIDTH*NUM_CALSS-1:0]	counting_count;
	reg										counting_valid;
	always @(posedge aclk) begin
		if( ~aresetn ) begin
			counting_tlast  <= 1'bx;
			counting_tuser  <= {TUSER_WIDTH{1'bx}};
			counting_count  <= {(TCOUNT_WIDTH*NUM_CALSS){1'bx}};
			counting_valid  <= 1'b0;
		end
		else if ( cke ) begin
			counting_tlast <= s_axi4s_tlast;
			counting_tuser <= s_axi4s_tuser;
			counting_tdata <= s_axi4s_tdata;
			for ( i = 0; i < NUM_CALSS; i = i+1 ) begin
				sum = 0;
				for ( j = 0; j < CHANNEL_WIDTH; j = j+1 ) begin
					sum = sum + s_axi4s_tdata[j*NUM_CALSS + i];
				end
				counting_count[TCOUNT_WIDTH*i +:TCOUNT_WIDTH] <= sum;
			end
			counting_valid  <= s_axi4s_tvalid;
		end
	end
	
	
	// select max
	jelly_minmax
			#(
				.NUM				(NUM_CALSS),
				.COMMON_USER_WIDTH	(1+TUSER_WIDTH+TDATA_WIDTH),
				.USER_WIDTH			(0),
				.DATA_WIDTH			(TCOUNT_WIDTH),
				.DATA_SIGNED		(0),
				.CMP_MIN			(0),	// minかmaxか
				.CMP_EQ				(0)		// 同値のとき data0 と data1 どちらを優先するか
			)
		i_minmax
			(
				.reset				(~aresetn),
				.clk				(aclk),
				.cke				(cke),
				
				.s_common_user		({counting_tlast, counting_tuser, counting_tdata}),
				.s_user				({NUM_CALSS{1'b0}}),
				.s_data				(counting_count),
				.s_en				({NUM_CALSS{1'b1}}),
				.s_valid			(counting_valid),
				
				.m_common_user		({m_axi4s_tlast, m_axi4s_tuser, m_axi4s_tdata}),
				.m_user				(),
				.m_data				(m_axi4s_tcount),
				.m_index			(m_axi4s_tnumber),
				.m_en				(),
				.m_valid			(m_axi4s_tvalid)
			);
	
	assign cke = !m_axi4s_tvalid | m_axi4s_tready;
	
	assign s_axi4s_tready = cke;
	
endmodule
module bb_lut
        #(
            parameter                   DEVICE = "RTL",
            parameter                   N      = 6,
            parameter   [(1<<N)-1:0]    INIT   = {(1<<N){1'b0}}
        )
        (
            input   wire    [N-1:0]     in_data,
            output  wire                out_data
        );
    
    generate
    if ( DEVICE == "7SERIES" && N == 6 ) begin : xilinx_7series
        LUT6
                #(
                    .INIT   (INIT)
                )
            i_lut6
                (
                    .O      (out_data),
                    .I0     (in_data[0]),
                    .I1     (in_data[1]),
                    .I2     (in_data[2]),
                    .I3     (in_data[3]),
                    .I4     (in_data[4]),
                    .I5     (in_data[5])
                );
    end
    else begin : rtl
        wire    [(1<<N)-1:0]    lut_table = INIT;
        assign out_data = lut_table[in_data];
    end
    endgenerate
    
    
endmodule
module video_mnist_color_core
		#(
			parameter	DATA_WIDTH  = 8,
			parameter	TUSER_WIDTH = 1,
			parameter	TDATA_WIDTH = 4*DATA_WIDTH
		)
		(
			input	wire						aresetn,
			input	wire						aclk,
			
			input	wire	[1:0]				param_mode,
			input	wire	[1:0]				param_th,
			
			input	wire	[TUSER_WIDTH-1:0]	s_axi4s_tuser,
			input	wire						s_axi4s_tlast,
			input	wire	[3:0]				s_axi4s_tnumber,
			input	wire	[1:0]				s_axi4s_tcount,
			input	wire	[TDATA_WIDTH-1:0]	s_axi4s_tdata,
			input	wire	[0:0]				s_axi4s_tbinary,
			input	wire						s_axi4s_tvalid,
			output	wire						s_axi4s_tready,
			
			output	wire	[TUSER_WIDTH-1:0]	m_axi4s_tuser,
			output	wire						m_axi4s_tlast,
			output	wire	[TDATA_WIDTH-1:0]	m_axi4s_tdata,
			output	wire						m_axi4s_tvalid,
			input	wire						m_axi4s_tready
		);
	
	
	reg		[TUSER_WIDTH-1:0]		st0_user;
	reg								st0_last;
	reg		[TDATA_WIDTH-1:0]		st0_data;
	reg								st0_en;
	reg		[23:0]					st0_color;
	reg								st0_valid;
	
	reg		[TUSER_WIDTH-1:0]		st1_user;
	reg								st1_last;
	reg		[TDATA_WIDTH-1:0]		st1_data;
	reg								st1_valid;
	
	always @(posedge aclk) begin
		if ( ~aresetn ) begin
			st0_user   <= {TUSER_WIDTH{1'bx}};
			st0_last   <= 1'bx;
			st0_data   <= {TDATA_WIDTH{1'bx}};
			st0_en     <= 1'bx;
			st0_color  <= 24'hxx_xx_xx;
			st0_valid  <= 1'b0;
			
			st1_user   <= {TUSER_WIDTH{1'bx}};
			st1_last   <= 1'bx;
			st1_data   <= {TDATA_WIDTH{1'bx}};
			st1_valid  <= 1'b0;
		end
		else if ( s_axi4s_tready ) begin
			st0_user   <= s_axi4s_tuser;
			st0_last   <= s_axi4s_tlast;
			st0_data   <= param_mode[0] ? {TDATA_WIDTH{s_axi4s_tbinary}} : s_axi4s_tdata;
			st0_en     <= (param_mode[1] && (s_axi4s_tcount >= param_th));
			case ( s_axi4s_tnumber )
			4'd0:		st0_color <= 24'h00_00_00;	// 黒
			4'd1:		st0_color <= 24'h00_00_80;	// 茶
			4'd2:		st0_color <= 24'h00_00_ff;	// 赤
			4'd3:		st0_color <= 24'h4c_b7_ff;	// 橙
			4'd4:		st0_color <= 24'h00_ff_ff;	// 黄
			4'd5:		st0_color <= 24'h00_80_00;	// 緑
			4'd6:		st0_color <= 24'hff_00_00;	// 青
			4'd7:		st0_color <= 24'h80_00_80;	// 紫
			4'd8:		st0_color <= 24'h80_80_80;	// 灰
			4'd9:		st0_color <= 24'hff_ff_ff;	// 白
			default:	st0_color <= 24'hxx_xx_xx;
			endcase
			st0_valid  <= s_axi4s_tvalid;
			
			st1_user   <= st0_user;
			st1_last   <= st0_last;
			st1_data   <= st0_data; // 24'h40_40_40;
			if ( st0_en ) begin
	//			st1_data[ 7: 0] <= (({1'b0, st0_data[ 7: 0]} + {1'b0, st0_color[ 7: 0]}) >> 1);
	//			st1_data[15: 8] <= (({1'b0, st0_data[15: 8]} + {1'b0, st0_color[15: 8]}) >> 1);
	//			st1_data[23:16] <= (({1'b0, st0_data[23:16]} + {1'b0, st0_color[23:16]}) >> 1);
	//			st1_data <= st0_color;
				st1_data <= {st0_color[7:0], st0_color[15:8], st0_color[23:16]};
			end
			st1_valid  <= st0_valid;
		end
	end
	
	assign s_axi4s_tready = (m_axi4s_tready || !m_axi4s_tvalid);
	
	assign m_axi4s_tuser  = st1_user;
	assign m_axi4s_tlast  = st1_last;
	assign m_axi4s_tdata  = st1_data;
	assign m_axi4s_tvalid = st1_valid;
	
endmodule
module img_mnist_core
		#(
			parameter	USER_WIDTH = 0,
			parameter	MAX_X_NUM  = 1024,
			parameter	USE_VALID  = 0,
			parameter	RAM_TYPE   = "block",
			
			parameter	USER_BITS  = USER_WIDTH > 0 ? USER_WIDTH : 1
		)
		(
			input	wire							reset,
			input	wire							clk,
			input	wire							cke,
			
			input	wire							s_img_line_first,
			input	wire							s_img_line_last,
			input	wire							s_img_pixel_first,
			input	wire							s_img_pixel_last,
			input	wire							s_img_de,
			input	wire	[USER_BITS-1:0]			s_img_user,
			input	wire	[0:0]					s_img_data,
			input	wire							s_img_valid,
			
			output	wire							m_img_line_first,
			output	wire							m_img_line_last,
			output	wire							m_img_pixel_first,
			output	wire							m_img_pixel_last,
			output	wire							m_img_de,
			output	wire	[USER_BITS-1:0]			m_img_user,
			output	wire	[0:0]					m_img_data,
			output	wire	[3:0]					m_img_number,
			output	wire	[1:0]					m_img_count,
			output	wire							m_img_valid
		);
	
	
	wire							img_blk_line_first;
	wire							img_blk_line_last;
	wire							img_blk_pixel_first;
	wire							img_blk_pixel_last;
	wire							img_blk_de;
	wire	[USER_BITS-1:0]			img_blk_user;
	wire	[28*28-1:0]				img_blk_data;
	wire							img_blk_valid;
	
	jelly_img_blk_buffer
			#(
				.USER_WIDTH			(USER_WIDTH),
				.DATA_WIDTH			(1),
				.LINE_NUM			(28),
				.PIXEL_NUM			(28),
				.PIXEL_CENTER		(13),
				.LINE_CENTER		(13),
				.MAX_X_NUM			(MAX_X_NUM),
				.RAM_TYPE			(RAM_TYPE),
				.BORDER_MODE		("CONSTANT")	// ("REFLECT_101")
			)
		i_img_blk_buffer
			(
				.reset				(reset),
				.clk				(clk),
				.cke				(cke),
				
				.s_img_line_first	(s_img_line_first),
				.s_img_line_last	(s_img_line_last),
				.s_img_pixel_first	(s_img_pixel_first),
				.s_img_pixel_last	(s_img_pixel_last),
				.s_img_de			(s_img_de),
				.s_img_user			(s_img_user),
				.s_img_data			(s_img_data),
				.s_img_valid		(s_img_valid),
				
				.m_img_line_first	(img_blk_line_first),
				.m_img_line_last	(img_blk_line_last),
				.m_img_pixel_first	(img_blk_pixel_first),
				.m_img_pixel_last	(img_blk_pixel_last),
				.m_img_de			(img_blk_de),
				.m_img_user			(img_blk_user),
				.m_img_data			(img_blk_data),
				.m_img_valid		(img_blk_valid)
			);
	
	
	img_mnist_unit
			#(
				.USER_WIDTH(USER_WIDTH+6)
			)
		i_img_mnist_unit
			(
				.reset				(reset),
				.clk				(clk),
				.cke				(cke),
				
				.in_user			({
										img_blk_user,
										img_blk_data[13*28 + 13],
										img_blk_line_first,
										img_blk_line_last,
										img_blk_pixel_first,
										img_blk_pixel_last,
										img_blk_de
									}),
				.in_data			(img_blk_data),
				.in_valid			(img_blk_valid),
				
				.out_user			({
										m_img_user,
										m_img_data,
										m_img_line_first,
										m_img_line_last,
										m_img_pixel_first,
										m_img_pixel_last,
										m_img_de
									}),
				.out_count			(m_img_count),
				.out_number			(m_img_number),
				.out_valid			(m_img_valid)
			);
	
	
endmodule
module video_mnist_color
		#(
			parameter	DATA_WIDTH      = 8,
			parameter	TUSER_WIDTH     = 1,
			parameter	TDATA_WIDTH     = 4*DATA_WIDTH,
			
			parameter	WB_ADR_WIDTH    = 8,
			parameter	WB_DAT_WIDTH    = 32,
			parameter	WB_SEL_WIDTH    = (WB_DAT_WIDTH / 8),
			parameter	INIT_PARAM_MODE = 2'b10,
			parameter	INIT_PARAM_TH   = 3
		)
		(
			input	wire						aresetn,
			input	wire						aclk,
			
			input	wire	[TUSER_WIDTH-1:0]	s_axi4s_tuser,
			input	wire						s_axi4s_tlast,
			input	wire	[3:0]				s_axi4s_tnumber,
			input	wire	[1:0]				s_axi4s_tcount,
			input	wire	[TDATA_WIDTH-1:0]	s_axi4s_tdata,
			input	wire	[0:0]				s_axi4s_tbinary,
			input	wire						s_axi4s_tvalid,
			output	wire						s_axi4s_tready,
			
			output	wire	[TUSER_WIDTH-1:0]	m_axi4s_tuser,
			output	wire						m_axi4s_tlast,
			output	wire	[TDATA_WIDTH-1:0]	m_axi4s_tdata,
			output	wire						m_axi4s_tvalid,
			input	wire						m_axi4s_tready,
			
			input	wire						s_wb_rst_i,
			input	wire						s_wb_clk_i,
			input	wire	[WB_ADR_WIDTH-1:0]	s_wb_adr_i,
			input	wire	[WB_DAT_WIDTH-1:0]	s_wb_dat_i,
			output	wire	[WB_DAT_WIDTH-1:0]	s_wb_dat_o,
			input	wire						s_wb_we_i,
			input	wire	[WB_SEL_WIDTH-1:0]	s_wb_sel_i,
			input	wire						s_wb_stb_i,
			output	wire						s_wb_ack_o
		);
	
	
	reg		[1:0]			reg_param_mode;
	reg		[1:0]			reg_param_th;
	always @(posedge s_wb_clk_i) begin
		if ( s_wb_rst_i ) begin
			reg_param_mode <= INIT_PARAM_MODE;
			reg_param_th   <= INIT_PARAM_TH;
		end
		else begin
			if ( s_wb_stb_i && s_wb_we_i ) begin
				case ( s_wb_adr_i )
				0:	reg_param_mode <= s_wb_dat_i;
				1:	reg_param_th   <= s_wb_dat_i;
				endcase
			end
		end
	end
	
	assign s_wb_dat_o = (s_wb_adr_i == 0) ? reg_param_mode :
	                    (s_wb_adr_i == 1) ? reg_param_th   :
	                    0;
	assign s_wb_ack_o = s_wb_stb_i;
	
	
	(* ASYNC_REG="true" *)	reg			[1:0]	ff0_param_mode, ff1_param_mode;
	(* ASYNC_REG="true" *)	reg			[1:0]	ff0_param_th,   ff1_param_th;
	always @(posedge aclk) begin
		ff0_param_mode <= reg_param_mode;
		ff1_param_mode <= ff0_param_mode;
		
		ff0_param_th   <= reg_param_th;
		ff1_param_th   <= ff0_param_th;
	end
	
	
	video_mnist_color_core
			#(
				.DATA_WIDTH			(DATA_WIDTH	),
				.TUSER_WIDTH		(TUSER_WIDTH),
				.TDATA_WIDTH		(TDATA_WIDTH)
			)
		i_video_mnist_color_core
			(
				.aresetn			(aresetn),
				.aclk				(aclk),
				
				.param_mode			(ff1_param_mode),
				.param_th			(ff1_param_th),
				
				.s_axi4s_tuser		(s_axi4s_tuser),
				.s_axi4s_tlast		(s_axi4s_tlast),
				.s_axi4s_tnumber	(s_axi4s_tnumber),
				.s_axi4s_tcount		(s_axi4s_tcount),
				.s_axi4s_tdata		(s_axi4s_tdata),
				.s_axi4s_tbinary	(s_axi4s_tbinary),
				.s_axi4s_tvalid		(s_axi4s_tvalid),
				.s_axi4s_tready		(s_axi4s_tready),
				
				.m_axi4s_tuser		(m_axi4s_tuser),
				.m_axi4s_tlast		(m_axi4s_tlast),
				.m_axi4s_tdata		(m_axi4s_tdata),
				.m_axi4s_tvalid		(m_axi4s_tvalid),
				.m_axi4s_tready		(m_axi4s_tready)
			);
	
	
	
endmodule
module tb_img_mnist_unit();
	localparam RATE = 1000.0/300.0;
	
	initial begin
		$dumpfile("tb_img_mnist_unit.vcd");
		$dumpvars(2, tb_img_mnist_unit);
		
	#20000000
		$finish;
	end
	
	reg		reset = 1'b1;
	initial	#(RATE*100)	reset = 1'b0;
	
	reg		clk = 1'b1;
	always #(RATE/2.0)	clk = ~clk;
	
	wire	cke = 1'b1;
	
	
	
	localparam	FILE_NAME    = "mnist_test.txt";
	localparam	DATA_SIZE    = 10000;
	localparam	USER_WIDTH   = 8;
	localparam	INPUT_WIDTH  = 28*28;
	localparam	OUTPUT_WIDTH = 30;
	
	reg		[USER_WIDTH+INPUT_WIDTH-1:0]	mem		[0:DATA_SIZE-1];
	initial begin
		$readmemb(FILE_NAME, mem);
	end
	
	reg		[28*28-1:0]	input_mem	[0:255];
	reg		[1080-1:0]	lut0_mem	[0:255];
	reg		[180-1:0]	lut1_mem	[0:255];
	reg		[30-1:0]	lut2_mem	[0:255];
	initial begin
		$readmemb("mnist_mpl_mini_input.txt", input_mem);
		$readmemb("mnist_mpl_mini_lut0.txt", lut0_mem);
		$readmemb("mnist_mpl_mini_lut1.txt", lut1_mem);
		$readmemb("mnist_mpl_mini_lut2.txt", lut2_mem);
	end
	
	reg		[180-1:0]	lut1_in_mem	[0:255];
	reg		[180-1:0]	lut1_out_mem	[0:255];
	initial begin
		$readmemb("mnist_mpl_mini_lut1_in.txt", lut1_in_mem);
		$readmemb("mnist_mpl_mini_lut1_out.txt", lut1_out_mem);
	end
	
	wire		[28*28-1:0]	input_sig0 = input_mem[0];
	wire		[1080-1:0]	lut0_sig0  = lut0_mem[0];
	wire		[180-1:0]	lut1_sig0  = lut1_mem[0];
	wire		[30-1:0]	lut2_sig0  = lut2_mem[0];
	
	wire		[180-1:0]	lut1_in_sig0  = lut1_in_mem[0];
	wire		[180-1:0]	lut1_out_sig0  = lut1_out_mem[0];
	
	integer									index = 0;
	wire		[USER_WIDTH-1:0]			in_user;
	wire		[INPUT_WIDTH-1:0]			in_data;
	reg										in_valid = 0;
	
	assign {in_user, in_data} = in_valid ? mem[index] : {(USER_WIDTH+INPUT_WIDTH){1'bx}};
	
	always @(posedge clk) begin
		if ( reset ) begin
			index    <= 0;
			in_valid <= 1'b0;
		end
		else begin
			index    <= index + in_valid;
			in_valid <= 1'b1;
			
			if ( index == DATA_SIZE-1 ) begin
				index <= 0;
			end
		end
	end
	
	
	wire	[USER_WIDTH-1:0]		out_user;
	wire	[1:0]					out_count;
	wire	[3:0]					out_number;
	wire							out_valid;
	
	img_mnist_unit
			#(
				.USER_WIDTH		(USER_WIDTH)
			)
		i_img_mnist_unit
			(
				.reset			(reset),
				.clk			(clk),
				.cke			(cke),
				
				.in_user		(in_user),
				.in_data		(in_data),
				.in_valid		(in_valid),
				
				.out_user		(out_user),
				.out_count		(out_count),
				.out_number		(out_number),
				.out_valid		(out_valid)
			);
	
	
	wire match = (out_number == out_user) && (out_count > 0);
	
	
endmodule
module jelly_integer_step
        #(
            parameter   DATA_WIDTH = 32
        )
        (
            input   wire                                clk,
            
            input   wire    [5:0]                       cke,
            
            // input
            input   wire    signed  [DATA_WIDTH-1:0]    s_param_init,
            input   wire    signed  [DATA_WIDTH-1:0]    s_param_step,
            input   wire                                s_initial,
            input   wire                                s_increment,
            
            // output
            output  wire    signed  [DATA_WIDTH-1:0]    m_data
        );
    
    reg     signed  [DATA_WIDTH-1:0]    reg_data;
    
    always @(posedge clk) begin
        if ( cke ) begin
            if ( s_initial ) begin
                reg_data <= s_param_init;
            end
            else begin
                if ( s_increment ) begin
                    reg_data <= reg_data + s_param_step;
                end
            end
        end
    end
    
    assign m_data = reg_data;
    
endmodule
module jelly_unsigned_sqrt_multicycle
        #(
            parameter   DATA_WIDTH = 32
        )
        (
            input   wire                        reset,
            input   wire                        clk,
            input   wire                        cke,
            
            // input
            input   wire    [2*DATA_WIDTH-1:0]  s_data,
            input   wire                        s_valid,
            output  wire                        s_ready,
            
            // output
            output  wire    [DATA_WIDTH-1:0]    m_data,
            output  wire                        m_valid,
            input   wire                        m_ready
        );
    
    reg                             reg_busy;
    reg                             reg_ready;
    reg                             reg_valid;
    
    reg     [DATA_WIDTH-1:0]        reg_counter;
    reg     [DATA_WIDTH-1:0]        reg_q;
    reg     [2*DATA_WIDTH-1:0]      reg_r;
    reg     [2*DATA_WIDTH-2-1:0]    reg_z;
    
    
    wire    [2*DATA_WIDTH-1:0]    remainder = reg_r - {1'b0, reg_q, 2'b01};
    wire                          r_sign    = ~remainder[2*DATA_WIDTH-1];
    
    always @(posedge clk) begin
        if ( reset ) begin
            reg_busy    <= 1'b0;
            reg_ready   <= 1'b0;
            reg_valid   <= 1'b0;
            reg_counter <= {DATA_WIDTH{1'bx}};
            reg_q       <= {DATA_WIDTH{1'bx}};
            reg_r       <= {(2*DATA_WIDTH){1'bx}};
            reg_z       <= {(2*DATA_WIDTH-2){1'bx}};
        end
        else if ( cke ) begin
            if ( !reg_busy && !reg_valid ) begin
                reg_ready <= 1'b1;
            end
            
            if ( m_valid & m_ready ) begin
                reg_valid <= 1'b0;
                reg_ready <= 1'b1;
            end
            
            if ( s_valid & s_ready & !m_valid ) begin
                // start
                {reg_r, reg_z} <= s_data;
                reg_q          <= 0;
                reg_busy       <= 1'b1;
                reg_ready      <= 1'b0;
                reg_counter    <= 0;
            end
            else if ( reg_busy ) begin
                reg_q <= {reg_q, r_sign};
                if ( r_sign ) begin
                    {reg_r, reg_z} <= {remainder, reg_z} << 2;
                end
                else begin
                    {reg_r, reg_z} <= {reg_r, reg_z} << 2;
                end
                reg_counter = {reg_counter, 1'b1};
                if ( reg_counter[DATA_WIDTH-1] ) begin
                    reg_busy  <= 1'b0;
                    reg_valid <= 1'b1;
                end
            end
        end
    end
    
    assign s_ready = reg_ready;
    
    assign m_data  = reg_q;
    assign m_valid = reg_valid;
    
endmodule
module jelly_integer_clz
        #(
            parameter   PIPELINES   = 1,
            parameter   COUNT_WIDTH = 5,
            parameter   DATA_WIDTH  = (1 << COUNT_WIDTH),
            parameter   UNIT_WIDTH  = 16
        )
        (
            input   wire                        clk,
            input   wire    [PIPELINES-1:0]     cke,
            
            // input
            input   wire    [DATA_WIDTH-1:0]    in_data,
            
            // output
            output  wire    [COUNT_WIDTH-1:0]   out_clz
        );
    
    localparam  UNIT_NUM  = (DATA_WIDTH + (UNIT_WIDTH-1)) / UNIT_WIDTH;
    localparam  EXT_WIDTH = UNIT_NUM * UNIT_WIDTH;
    
    
    generate
    if ( PIPELINES == 1 ) begin : blk_pipeline1
        // 1 cycle
        integer                     i;
        reg     [COUNT_WIDTH-1:0]   st0_clz;
        
        always @(posedge clk) begin
            if ( cke[0] ) begin
                st0_clz <= {COUNT_WIDTH{1'b1}};
                begin : block_clz
                    for ( i = 0; i < DATA_WIDTH; i = i+1 ) begin
                        if ( in_data[(DATA_WIDTH-1)-i] != 1'b0 ) begin
                            st0_clz <= i;
                            disable block_clz;
                        end
                    end
                end
            end
        end
        
        assign out_clz = st0_clz;
    end
    else begin : blk_pipeline2
        // 2 cycle
        integer                                 i, j;
        
        wire    [EXT_WIDTH-1:0]                 sig_data = (in_data << (EXT_WIDTH - DATA_WIDTH));
        
        reg     [UNIT_NUM-1:0]                  st0_en;
        reg     [UNIT_NUM*COUNT_WIDTH-1:0]      st0_count;
        
        reg     [COUNT_WIDTH-1:0]               st1_count;
        
        always @(posedge clk) begin
            if ( cke[0] ) begin
                for ( i = 0; i < UNIT_NUM; i = i+1 ) begin
                    st0_en   [i]                            <= 1'b0;
                    st0_count[i*COUNT_WIDTH +: COUNT_WIDTH] <= {COUNT_WIDTH{1'b1}};
                    begin : block_st0_count
                        for ( j = 0; j < UNIT_WIDTH; j = j+1 ) begin
                            if ( sig_data[(EXT_WIDTH-1)-(i*UNIT_WIDTH+j)] != 1'b0 ) begin
                                st0_en   [i]                            <= 1'b1;
                                st0_count[i*COUNT_WIDTH +: COUNT_WIDTH] <= i*UNIT_WIDTH+j;
                                disable block_st0_count;
                            end
                        end
                    end
                end
            end
            
            if ( cke[1] ) begin
                st1_count <= {COUNT_WIDTH{1'b1}};
                begin : block_st1_select
                    for ( i = 0; i < UNIT_NUM; i = i+1 ) begin
                        if ( st0_en[i] ) begin
                            st1_count <= st0_count[i*COUNT_WIDTH +: COUNT_WIDTH];
                            disable block_st1_select;
                        end
                    end
                end
            end
        end
        
        assign out_clz = st1_count;
    end
    endgenerate
    
endmodule
module jelly_count_leading_zeroes
        #(
            parameter   DATA_WIDTH    = 16,
            parameter   OUT_WIDTH     = 6,
            parameter   IN_REGS       = 1,
            parameter   OUT_REGS      = 1,
            parameter   INIT_IN_REGS  = {DATA_WIDTH{1'bx}},
            parameter   INIT_OUT_REGS = {OUT_WIDTH{1'bx}}
        )
        (
            input   wire                        reset,
            input   wire                        clk,
            input   wire                        inreg_cke,
            input   wire                        outreg_cke,
            
            input   wire    [DATA_WIDTH-1:0]    in_data,
            
            output  wire    [OUT_WIDTH-1:0]     out_clz
        );
    
    wire    [DATA_WIDTH-1:0]    sig_data;
    generate
    if ( OUT_REGS ) begin
        reg     [DATA_WIDTH-1:0]    reg_data;
        always @(posedge clk) begin
            if ( reset ) begin
                reg_data <= INIT_IN_REGS;
            end
            else if ( inreg_cke ) begin
                reg_data <= in_data;
            end
        end
        assign sig_data = reg_data;
    end
    else begin
        assign sig_data = in_data;
    end
    endgenerate
    
    
    integer                     i;
    reg     [OUT_WIDTH-1:0]     sig_clz;
    
    always @* begin
        sig_clz = {OUT_WIDTH{1'b0}};
        for ( i = 0; i < DATA_WIDTH; i=i+1 ) begin : clz_loop
            if ( sig_data[DATA_WIDTH-1 - i] != 1'b0 ) begin
                sig_clz = i;
                disable clz_loop;
            end
        end
    end
    
    generate
    if ( OUT_REGS ) begin
        reg     [OUT_WIDTH-1:0]     reg_clz;
        always @(posedge clk) begin
            if ( reset ) begin
                reg_clz <= INIT_OUT_REGS;
            end
            else if ( outreg_cke ) begin
                reg_clz <= sig_clz;
            end
        end
        assign out_clz = reg_clz;
    end
    else begin
        assign out_clz = sig_clz;
    end
    endgenerate
    
endmodule
module jelly_integer_accumulator
        #(
            parameter                           SIGEND            = 0,
            parameter                           ACCUMULATOR_WIDTH = 64,
            parameter                           DATA_WIDTH        = ACCUMULATOR_WIDTH,
            parameter                           UNIT_WIDTH        = 32,
            parameter   [ACCUMULATOR_WIDTH-1:0] INIT_VALUE        = {ACCUMULATOR_WIDTH{1'bx}}
        )
        (
            input   wire                                reset,
            input   wire                                clk,
            input   wire                                cke,
            
            input   wire                                set,
            input   wire                                add,
            output  wire                                busy,
            
            input   wire    [DATA_WIDTH-1:0]            data,
            
            output  wire    [ACCUMULATOR_WIDTH-1:0]     accumulator
        );
    
    localparam  UNIT_NUM  = (ACCUMULATOR_WIDTH + UNIT_WIDTH - 1) / UNIT_WIDTH;
    
    wire    signed  [UNIT_NUM*UNIT_WIDTH-1:0]   s_data  = $signed(data);
    wire            [UNIT_NUM*UNIT_WIDTH-1:0]   u_data  = SIGEND ? s_data : data;
    wire            [UNIT_NUM*UNIT_WIDTH-1:0]   in_data = (set || add) ? u_data : {ACCUMULATOR_WIDTH{1'b0}};
    
    integer                             i;
    reg     [UNIT_NUM-1:0]              reg_carry;
    reg     [UNIT_NUM*UNIT_WIDTH-1:0]   reg_accumulator;
    
    always @(posedge clk) begin
        if ( reset ) begin
            for ( i = 0; i < UNIT_NUM; i = i+1 ) begin
                reg_carry      [i]                          <= 1'b0;
                reg_accumulator[i*UNIT_WIDTH +: UNIT_WIDTH] <= (INIT_VALUE >> (i*UNIT_WIDTH));
            end
        end
        else if ( cke ) begin
            if ( set ) begin
                for ( i = 0; i < UNIT_NUM; i = i+1 ) begin
                    reg_carry      [i]                          <= 1'b0;
                    reg_accumulator[i*UNIT_WIDTH +: UNIT_WIDTH] <= in_data[i*UNIT_WIDTH +: UNIT_WIDTH];
                end
            end
            else begin
                {reg_carry[0], reg_accumulator[0*UNIT_WIDTH +: UNIT_WIDTH]} <= reg_accumulator[0*UNIT_WIDTH +: UNIT_WIDTH] + in_data[0*UNIT_WIDTH +: UNIT_WIDTH];
                for ( i = 1; i < UNIT_NUM; i = i+1 ) begin
                    {reg_carry[i], reg_accumulator[i*UNIT_WIDTH +: UNIT_WIDTH]} <= reg_accumulator[i*UNIT_WIDTH +: UNIT_WIDTH] + in_data[i*UNIT_WIDTH +: UNIT_WIDTH] + reg_carry[i-1];
                end
            end
        end
    end
    
    integer     j;
    reg         sig_busy;
    always @* begin
        sig_busy = 1'b0;
        for ( j = 0; j < UNIT_NUM-1; j = j+1 ) begin
            sig_busy = (sig_busy | reg_carry[j]);
        end
    end
    
    assign busy        = sig_busy;
    assign accumulator = reg_accumulator;
    
endmodule
module jelly_unsigned_multiply_multicycle
        #(
            parameter   DATA_WIDTH0 = 32,
            parameter   DATA_WIDTH1 = 32
        )
        (
            input   wire                                    reset,
            input   wire                                    clk,
            input   wire                                    cke,
            
            // input
            input   wire    [DATA_WIDTH0-1:0]               s_data0,
            input   wire    [DATA_WIDTH1-1:0]               s_data1,
            input   wire                                    s_valid,
            output  wire                                    s_ready,
            
            // output
            output  wire    [DATA_WIDTH0+DATA_WIDTH1-1:0]   m_data,
            output  wire                                    m_valid,
            input   wire                                    m_ready
        );
    
    reg                                     reg_busy;
    reg                                     reg_ready;
    reg                                     reg_valid;
    
    reg     [DATA_WIDTH1-1:0]               reg_k;
    reg     [DATA_WIDTH0+DATA_WIDTH1-1:0]   reg_m;
    reg     [DATA_WIDTH0+DATA_WIDTH1-1:0]   reg_q;
    
    always @(posedge clk) begin
        if ( reset ) begin
            reg_busy    <= 1'b0;
            reg_ready   <= 1'b0;
            reg_valid   <= 1'b0;
            reg_k       <= {DATA_WIDTH1{1'bx}};
            reg_m       <= {(DATA_WIDTH0+DATA_WIDTH1){1'bx}};
            reg_q       <= {(DATA_WIDTH0+DATA_WIDTH1){1'bx}};
        end
        else if ( cke ) begin
            if ( !reg_busy && !reg_valid ) begin
                reg_ready <= 1'b1;
            end
            
            if ( m_valid & m_ready ) begin
                reg_valid <= 1'b0;
                reg_ready <= 1'b1;
            end
            
            if ( s_valid & s_ready & !m_valid ) begin
                // start
                reg_m       <= s_data0;
                reg_k       <= s_data1;
                reg_q       <= 0;
                reg_busy    <= 1'b1;
                reg_ready   <= 1'b0;
            end
            else if ( reg_busy ) begin
                if ( reg_k[0] ) begin
                    reg_q <= reg_q + reg_m;
                end
                reg_k <= reg_k >> 1;
                reg_m <= reg_m << 1;
                
                if ( reg_k == 0 ) begin
                    reg_busy  <= 1'b0;
                    reg_valid <= 1'b1;
                end
            end
        end
    end
    
    assign s_ready = reg_ready;
    
    assign m_data  = reg_q;
    assign m_valid = reg_valid;
    
endmodule
module jelly_calc_crc
        #(
            parameter   DATA_WIDTH      = 8,
            parameter   CRC_WIDTH       = 32,
            parameter   REPRESENTATIONS = 32'hEDB88320
        )
        (
            input   wire                        reset,
            input   wire                        clk,
            input   wire                        cke,

            input   wire                        in_update,
            input   wire    [DATA_WIDTH-1:0]    in_data,
            input   wire                        in_valid,
            
            input   wire    [CRC_WIDTH-1:0]     out_crc
        );
    
    localparam TABLE_SIZE = (1 << DATA_WIDTH);

    reg     [CRC_WIDTH-1:0]     crc_table[0:TABLE_SIZE-1];

    integer                     i, j;
    reg     [CRC_WIDTH-1:0]     c;

    initial begin
        for ( i = 0; i < TABLE_SIZE; i = i+1 ) begin
            c = i;
            for ( j = 0; j < DATA_WIDTH; j = j+1 ) begin
                c = (c & 1) ? (REPRESENTATIONS ^ (c >> 1)) : (c >> 1);
            end
        end
        crc_table[i] = c;
    end

    reg     [CRC_WIDTH-1:0]     reg_crc;
    reg     [CRC_WIDTH-1:0]     tmp_crc;
    reg     [DATA_WIDTH-1:0]    tmp_index;

    always @(posedge clk) begin
        if ( reset ) begin
            reg_crc <= {CRC_WIDTH{1'b1}};
        end
        else if ( cke ) begin
            if ( in_valid ) begin
                tmp_crc    = in_update ? reg_crc : {CRC_WIDTH{1'b1}};
                tmp_index  = tmp_crc ^ in_data;
                reg_crc   <= crc_table[tmp_index] ^ (tmp_crc >> DATA_WIDTH);
            end
        end
    end

    assign out_crc = ~reg_crc;
    
endmodule
module jelly_linear_interpolation_signed
        #(
            parameter   DATA_WIDTH = 8,
            parameter   COMPACT    = 0,
            parameter   BLENDING   = 0
        )
        (
            input   wire                                clk,
            input   wire                                cke,
            
            input   wire                                s_sel,
            input   wire    signed  [DATA_WIDTH-1:0]    s_data0,
            input   wire    signed  [DATA_WIDTH-1:0]    s_data1,
            
            output  wire    signed  [DATA_WIDTH-1:0]    m_data0,
            output  wire    signed  [DATA_WIDTH-1:0]    m_data1
        );

    reg     signed  [DATA_WIDTH:0]      reg_data0;
    reg     signed  [DATA_WIDTH:0]      reg_data1;  
    wire    signed  [DATA_WIDTH-1:0]    tmp_data = s_sel ? s_data1 : s_data0;
    
    always @(posedge clk) begin
        if ( cke ) begin
            reg_data0 <= s_data0 + tmp_data;
            reg_data1 <= s_data1 + tmp_data;
        end
    end
    
    assign m_data0 = reg_data0[COMPACT +: DATA_WIDTH];
    assign m_data1 = reg_data1[COMPACT +: DATA_WIDTH];
    
endmodule
module jelly_linear_interpolation_unsigned
        #(
            parameter   DATA_WIDTH = 8,
            parameter   COMPACT    = 0,
            parameter   BLENDING   = 0
        )
        (
            input   wire                        clk,
            input   wire                        cke,
            
            input   wire                        s_sel,
            input   wire    [DATA_WIDTH-1:0]    s_data0,
            input   wire    [DATA_WIDTH-1:0]    s_data1,
            
            output  wire    [DATA_WIDTH-1:0]    m_data0,
            output  wire    [DATA_WIDTH-1:0]    m_data1
        );

    reg     [DATA_WIDTH:0]      reg_data0;
    reg     [DATA_WIDTH:0]      reg_data1;
    wire    [DATA_WIDTH-1:0]    tmp_data = s_sel ? s_data1 : s_data0;
    
    always @(posedge clk) begin
        if ( cke ) begin
            if ( BLENDING ) begin
                reg_data0 <= s_data0 + tmp_data + s_sel;
                reg_data1 <= s_data1 + tmp_data + s_sel;
            end
            else begin
                reg_data0 <= s_data0 + tmp_data;
                reg_data1 <= s_data1 + tmp_data;
            end
        end
    end
    
    assign m_data0 = reg_data0[COMPACT +: DATA_WIDTH];
    assign m_data1 = reg_data1[COMPACT +: DATA_WIDTH];
    
endmodule
module jelly_unsigned_divide_multicycle
        #(
            parameter   DATA_WIDTH = 32
        )
        (
            input   wire                        reset,
            input   wire                        clk,
            input   wire                        cke,
            
            // input
            input   wire    [DATA_WIDTH-1:0]    s_data0,
            input   wire    [DATA_WIDTH-1:0]    s_data1,
            input   wire                        s_valid,
            output  wire                        s_ready,
            
            // output
            output  wire    [DATA_WIDTH-1:0]    m_quotient,
            output  wire    [DATA_WIDTH-1:0]    m_remainder,
            output  wire                        m_valid,
            input   wire                        m_ready
        );
    
    reg                         reg_busy;
    reg                         reg_ready;
    reg                         reg_valid;
    
    reg     [DATA_WIDTH-1:0]    reg_counter;
    wire    [DATA_WIDTH-1:0]    next_counter = {reg_counter, 1'b1};
    
    reg     [DATA_WIDTH-1:0]    reg_remainder;
    reg     [DATA_WIDTH-1:0]    reg_quotient;
    reg     [DATA_WIDTH-1:0]    reg_divisor;
    
    wire    [DATA_WIDTH-1:0]    remainder1;
    wire    [DATA_WIDTH-1:0]    quotient1;
    wire    [DATA_WIDTH:0]      quotient2;
    
    
    assign {remainder1, quotient1} = {reg_remainder, reg_quotient, ~quotient2[DATA_WIDTH]};
    assign quotient2               = remainder1 - reg_divisor;
    
    always @ ( posedge clk ) begin
        if ( reset ) begin
            reg_busy      <= 1'b0;
            reg_ready     <= 1'b0;
            reg_valid     <= 1'b0;
            reg_counter   <= {DATA_WIDTH{1'bx}};
            reg_remainder <= {DATA_WIDTH{1'bx}};
            reg_quotient  <= {DATA_WIDTH{1'bx}};
            reg_divisor   <= {DATA_WIDTH{1'bx}};
        end
        else if ( cke ) begin
            if ( !reg_busy && !reg_valid ) begin
                reg_ready <= 1'b1;
            end
            
            if ( m_valid & m_ready ) begin
                reg_valid <= 1'b0;
                reg_ready <= 1'b1;
            end
            
            if ( s_valid & s_ready ) begin
                reg_remainder <= {DATA_WIDTH{1'b0}};
                reg_quotient  <= s_data0;
                reg_divisor   <= s_data1;
                reg_busy      <= 1'b1;
                reg_ready     <= 1'b0;
                reg_counter   <= 0;
            end
            else if ( reg_busy ) begin
                reg_remainder <= quotient2[DATA_WIDTH] ? remainder1 : quotient2[DATA_WIDTH-1:0];
                reg_quotient  <= quotient1;
                
                reg_counter <= next_counter;
                if ( next_counter[DATA_WIDTH-1] ) begin
                    reg_busy  <= 1'b0;
                    reg_valid <= 1'b1;
                end
            end
        end
    end
    
    assign s_ready     = reg_ready;
    
    assign m_quotient  = reg_quotient;
    assign m_remainder = reg_remainder;
    assign m_valid     = reg_valid;
    
endmodule
module jelly_uart_tx
        (
            // system
            input   wire                        reset,
            input   wire                        clk,
            input   wire                        dv_pulse,
            
            // UART
            output  wire                        uart_tx,
            
            // control
            input   wire    [7:0]               tx_data,
            input   wire                        tx_valid,
            output  wire                        tx_ready
        );
    
    // TX
    reg                         tx_busy;
    reg     [6:0]               tx_count;
    reg     [8:0]               tx_buf;
    
    always @ ( posedge clk ) begin
        if ( reset ) begin
            tx_busy      <= 1'b0;
            tx_count     <= {7{1'bx}};
            tx_buf[0]    <= 1'b1;
            tx_buf[8:1]  <= {8{1'bx}};
        end
        else if ( dv_pulse ) begin
            if ( !tx_busy ) begin
                if ( tx_valid ) begin
                    tx_busy      <= 1'b1;
                    tx_buf[0]    <= 1'b0;
                    tx_buf[8:1]  <= tx_data;
                    tx_count     <= 7'h00;
                end
            end
            else begin
                tx_count <= tx_count + 1'b1;
                if ( tx_count[2:0] == 4'h7 ) begin
                    tx_buf <= {1'b1, tx_buf[8:1]};
                    if ( tx_count[6:3] == 4'ha ) begin
                        tx_busy <= 1'b0;
                    end
                end
            end
        end
    end
    
    assign tx_ready = ~tx_busy & dv_pulse;
    assign uart_tx  = tx_buf[0];
    
endmodule
module jelly_clock_counter
        #(
            parameter                           WB_ADR_WIDTH  = 3,
            parameter                           WB_DAT_WIDTH  = 32,
            parameter                           WB_SEL_WIDTH  = (WB_DAT_WIDTH / 8)
        )
        (
            // system
            input   wire                        reset,
            input   wire                        clk,
            
            // control port (wishbone)
            input   wire    [WB_ADR_WIDTH-1:0]  s_wb_adr_i,
            output  reg     [WB_DAT_WIDTH-1:0]  s_wb_dat_o,
            input   wire    [WB_DAT_WIDTH-1:0]  s_wb_dat_i,
            input   wire                        s_wb_we_i,
            input   wire    [WB_SEL_WIDTH-1:0]  s_wb_sel_i,
            input   wire                        s_wb_stb_i,
            output  wire                        s_wb_ack_o
        );

    // register address
    localparam  CLOCK_COUNTER_ADR_CONTROL   = 3'b000;
    localparam  CLOCK_COUNTER_ADR_MONITOR_H = 3'b010;
    localparam  CLOCK_COUNTER_ADR_MONITOR_L = 3'b011;
    localparam  CLOCK_COUNTER_ADR_COUNTER_H = 3'b110;
    localparam  CLOCK_COUNTER_ADR_COUNTER_L = 3'b111;

    
    // control
    reg                 reg_copy_mon;
    reg                 reg_clear;
    
    reg     [63:0]      reg_counter;
    reg     [63:0]      reg_monitor;
    
    always @ ( posedge clk ) begin
        if ( reset ) begin
            reg_copy_mon <= 1'b0;
            reg_clear    <= 1'b0;
            
            reg_counter  <= 64'd0;
            reg_monitor  <= 64'd0;
        end
        else begin
            // control
            if ( s_wb_stb_i & s_wb_we_i & s_wb_sel_i[0] & (s_wb_adr_i == CLOCK_COUNTER_ADR_CONTROL) ) begin
                reg_copy_mon <= s_wb_dat_i[0];
                reg_clear    <= s_wb_dat_i[7];
            end
            else begin
                reg_copy_mon <= 1'b0;       // auto clear;
                reg_clear    <= 1'b0;       // auto clear;
            end
            
            // counter
            if ( reg_clear ) begin
                reg_counter <= 64'd0;
            end
            else begin
                reg_counter <= reg_counter + 1;
            end
            
            // monitor
            if ( reg_copy_mon ) begin
                reg_monitor <= reg_counter;
            end
        end
    end
    
    always @* begin
        case ( s_wb_adr_i )
        CLOCK_COUNTER_ADR_CONTROL:      begin   s_wb_dat_o <= {reg_clear, 6'd0, reg_copy_mon};  end
        CLOCK_COUNTER_ADR_MONITOR_H:    begin   s_wb_dat_o <= reg_monitor[63:32];               end
        CLOCK_COUNTER_ADR_MONITOR_L:    begin   s_wb_dat_o <= reg_monitor[31:0];                end
        CLOCK_COUNTER_ADR_COUNTER_H:    begin   s_wb_dat_o <= reg_counter[63:32];               end
        CLOCK_COUNTER_ADR_COUNTER_L:    begin   s_wb_dat_o <= reg_counter[31:0];                end
        default:                        begin   s_wb_dat_o <= {WB_DAT_WIDTH{1'b0}};             end
        endcase
    end
    
    assign s_wb_ack_o = s_wb_stb_i;
    
endmodule
module jelly_uart_rx
        (
            // system
            input   wire            reset,
            input   wire            clk,
            input   wire            dv_pulse,
            
            // UART
            input   wire            uart_rx,
            
            // control
            output  wire    [7:0]   rx_data,
            output  wire            rx_valid
        );
    
    // recv
    reg                         rx_ff_buf;
    reg     [8:0]               rx_buf;
    reg                         rx_busy;
    reg     [7:0]               rx_count;
    reg                         rx_wr_valid;
    always @ ( posedge clk ) begin
        if ( reset ) begin
            rx_ff_buf   <= 1'b1;
            rx_buf      <= {9{1'bx}};
            rx_busy     <= 1'b0;
            rx_count    <= 0;
            rx_wr_valid <= 1'b0;
        end
        else if ( dv_pulse ) begin
            rx_ff_buf <= uart_rx;
            
            if ( !rx_busy ) begin
                rx_wr_valid <= 1'b0;
                if ( rx_ff_buf == 1'b0 ) begin
                    rx_busy  <= 1'b1;
                    rx_count <= 0;
                end
            end
            else begin
                rx_count <= rx_count + 1'b1;
                if ( rx_count[2:0] == 3'h3 ) begin
                    rx_buf <= {rx_ff_buf, rx_buf[8:1]};
                    if ( rx_count[6:3] == 9 ) begin
                        rx_busy     <= 1'b0;
                        rx_wr_valid <= 1'b1;
                    end
                end
            end
        end
    end
    
    assign rx_valid = rx_wr_valid & dv_pulse;
    assign rx_data  = rx_buf[7:0];
    
endmodule