module histogram32
	(
		input	wire			clock, frame, reset,
		
		input	wire			hst_good,
		input	wire	[6:0]	hst_data,

		input	wire			bus_ssel, bus_wren,
		input	wire	[7:0]	bus_addr,
		input	wire	[15:0]	bus_mosi,

		output	wire	[15:0]	bus_miso,
		output	wire			bus_busy
	);
	
	// signal declaration
	reg		[3:0]	int_case_reg, int_case_next;
	reg				int_wren_reg, int_wren_next;
	reg		[6:0]	int_addr_reg, int_addr_next;
	reg		[31:0]	int_data_reg, int_data_next;

	reg		[7:0]	bus_addr_reg, bus_addr_next;
	reg		[15:0]	bus_miso_reg, bus_miso_next;

	reg				bus_wren_reg, bus_wren_next;
	reg		[15:0]	bus_mosi_reg, bus_mosi_next;

	wire	[31:0]	q_a_wire;
	wire	[15:0]	q_b_wire;

	altsyncram #(
		.address_reg_b("CLOCK0"),
		.clock_enable_input_a("BYPASS"),
		.clock_enable_input_b("BYPASS"),
		.clock_enable_output_a("BYPASS"),
		.clock_enable_output_b("BYPASS"),
		.indata_reg_b("CLOCK0"),
		.intended_device_family("Cyclone III"),
		.lpm_type("altsyncram"),
		.numwords_a(80),
		.numwords_b(160),
		.operation_mode("BIDIR_DUAL_PORT"),
		.outdata_aclr_a("NONE"),
		.outdata_aclr_b("NONE"),
		.outdata_reg_a("CLOCK0"),
		.outdata_reg_b("CLOCK0"),
		.power_up_uninitialized("FALSE"),
		.read_during_write_mode_mixed_ports("OLD_DATA"),
		.read_during_write_mode_port_a("NEW_DATA_NO_NBE_READ"),
		.read_during_write_mode_port_b("NEW_DATA_NO_NBE_READ"),
		.widthad_a(7),
		.widthad_b(8),
		.width_a(32),
		.width_b(16),
		.width_byteena_a(1),
		.width_byteena_b(1),
		.wrcontrol_wraddress_reg_b("CLOCK0")) hst_ram_unit(
		.wren_a(int_wren_reg),
		.clock0(clock),
		.wren_b(bus_wren_reg),
		.address_a(int_addr_reg),
		.address_b(bus_addr_reg),
		.data_a(int_data_reg),
		.data_b(bus_mosi_reg),
		.q_a(q_a_wire),
		.q_b(q_b_wire),
		.aclr0(1'b0),
		.aclr1(1'b0),
		.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),
		.eccstatus(),
		.rden_a(1'b1),
		.rden_b(1'b1));

	// body
	always @(posedge clock)
	begin
		if (reset)
        begin
			int_wren_reg <= 1'b1;
			int_addr_reg <= 7'd0;
			int_data_reg <= 32'd0;
			int_case_reg <= 4'b0;
			bus_addr_reg <= 8'd0;
			bus_miso_reg <= 16'd0;
			bus_wren_reg <= 1'b0;
			bus_mosi_reg <= 16'd0;
		end
		else
		begin
			int_wren_reg <= int_wren_next;
			int_addr_reg <= int_addr_next;
			int_data_reg <= int_data_next;
			int_case_reg <= int_case_next;
			bus_addr_reg <= bus_addr_next;
			bus_miso_reg <= bus_miso_next;
			bus_wren_reg <= bus_wren_next;
			bus_mosi_reg <= bus_mosi_next;
		end             
	end

	always @*
	begin
		bus_addr_next = bus_addr_reg;
		bus_miso_next = bus_miso_reg;

		bus_wren_next = 1'b0;
		bus_mosi_next = bus_mosi_reg;

		if (bus_ssel)
		begin
			bus_miso_next = q_b_wire;	
			bus_addr_next = bus_addr;
			bus_wren_next = bus_wren;	
			if (bus_wren)
			begin
				bus_mosi_next = bus_mosi;
			end
		end
	end

	always @*
	begin
		int_wren_next = int_wren_reg;
		int_addr_next = int_addr_reg;
		int_data_next = int_data_reg;
		int_case_next = int_case_reg;

		case (int_case_reg)
						
			0:
			begin
				// write zeros
				int_addr_next = int_addr_reg + 7'd1;
				if (&int_addr_reg)
				begin
					int_wren_next = 1'b0;
					int_case_next = 4'd1;
				end
			end	

			1:
			begin
				int_wren_next = 1'b0;
/*
				if (&int_data_reg)
				begin
					int_case_next = 4'd0;
				end
				else if (frame & hst_good)
*/
				if (frame & hst_good)
				begin
					int_addr_next = hst_data;
					int_case_next = 4'd2;
				end
			end

			2:
			begin
				int_case_next = 4'd3;
			end

			3:
			begin
				int_case_next = 4'd4;
			end

			4:
			begin
				int_case_next = 4'd1;
				if (~&q_a_wire)
				begin
					int_wren_next = 1'b1;
					int_data_next = q_a_wire + 32'd1;
				end
			end

			default:
			begin
				int_wren_next = 1'b0;
				int_addr_next = 7'd0;
				int_data_next = 32'd0;
				int_case_next = 4'd0;
			end
		endcase
	end

	// output logic
	assign	bus_miso = bus_miso_reg;
	assign	bus_busy = 1'b0;
endmodule
