module oscilloscope
	(
		input	wire			clock, frame, reset,
		
		input	wire			cfg_data,

		input	wire			trg_flag,

		input	wire	[63:0]	osc_data,

		output	wire			ram_wren,
		output	wire	[19:0]	ram_addr,
		inout	wire	[17:0]	ram_data,

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

		output	wire	[15:0]	bus_miso,
		output	wire			bus_busy
	);


	reg		[63:0]	osc_data_reg, osc_data_next;

	reg		[2:0]	int_case_reg, int_case_next;

	reg				int_trig_reg, int_trig_next;
	reg		[19:0]	int_trig_addr_reg, int_trig_addr_next;

	reg		[19:0]	int_cntr_reg [1:0];
	reg		[19:0]	int_cntr_next [1:0];

	reg		[15:0]	bus_miso_reg, bus_miso_next;
	reg				bus_busy_reg, bus_busy_next;

	reg				ram_wren_reg [2:0];
	reg				ram_wren_next [2:0];

	reg		[17:0]	ram_data_reg [2:0];
	reg		[17:0]	ram_data_next [2:0];

	reg		[19:0]	ram_addr_reg, ram_addr_next;

	wire	[17:0]	ram_wren_wire;

	assign	ram_wren = ~ram_wren_reg[0];
	assign	ram_addr = ram_addr_reg;

	integer i;
	genvar j;

	generate
		for (j = 0; j < 18; j = j + 1)
		begin : SRAM_WREN
			assign ram_wren_wire[j] = ram_wren_reg[2];
			assign ram_data[j] = ram_wren_wire[j] ? ram_data_reg[2][j] : 1'bz;
		end
	endgenerate

	always @(posedge clock)
	begin
		if (reset)
		begin
			osc_data_reg <= 64'd0;
			ram_addr_reg <= 20'd0;
			bus_miso_reg <= 16'd0;
			bus_busy_reg <= 1'b0;
			int_case_reg <= 5'd0;
			int_cntr_reg[0] <= 20'd0;
			int_cntr_reg[1] <= 20'd0;
			int_trig_reg <= 1'b0;
			int_trig_addr_reg <= 20'd0;
			
			for(i = 0; i <= 2; i = i + 1)
			begin
				ram_wren_reg[i] <= 1'b0;
				ram_data_reg[i] <= 16'd0;
			end
		end
		else
		begin
			osc_data_reg <= osc_data_next;
			ram_addr_reg <= ram_addr_next;
			bus_miso_reg <= bus_miso_next;
			bus_busy_reg <= bus_busy_next;
			int_case_reg <= int_case_next;
			int_cntr_reg[0] <= int_cntr_next[0];
			int_cntr_reg[1] <= int_cntr_next[1];
			int_trig_reg <= int_trig_next;
			int_trig_addr_reg <= int_trig_addr_next;

			for(i = 0; i <= 2; i = i + 1)
			begin
				ram_wren_reg[i] <= ram_wren_next[i];
				ram_data_reg[i] <= ram_data_next[i];
			end
		end
	end

	always @*
	begin

		osc_data_next = osc_data_reg;
		ram_addr_next = ram_addr_reg;
		bus_miso_next = bus_miso_reg;
		bus_busy_next = bus_busy_reg;
		int_case_next = int_case_reg;
		int_cntr_next[0] = int_cntr_reg[0];
		int_cntr_next[1] = int_cntr_reg[1];
		int_trig_next = int_trig_reg;
		int_trig_addr_next = int_trig_addr_reg;

		for(i = 0; i < 2; i = i + 1)
		begin
			ram_wren_next[i+1] = ram_wren_reg[i];
			ram_data_next[i+1] = ram_data_reg[i];
		end
		ram_wren_next[0] = 1'b0;
		ram_data_next[0] = 18'd0;

		case (int_case_reg)
			0:
			begin
				bus_busy_next = 1'b0;
				int_cntr_next[0] = 20'd0;
				int_cntr_next[1] = 20'd0;
				int_trig_next = 1'b0;

				if (bus_ssel)
				begin
					bus_miso_next = {ram_data[17:10], ram_data[8:1]};
					ram_wren_next[0] = bus_wren;
					if (bus_wren)
					begin
						ram_addr_next = bus_addr;
						ram_data_next[0] = {bus_mosi[15:8], 1'b0, bus_mosi[7:0], 1'b0};
					end
					else
					begin
						ram_addr_next = int_trig_addr_reg + bus_addr;	
//						ram_addr_next = bus_addr;	
					end
				end
				else if (cfg_data)
				begin
					// start recording
					ram_wren_next[0] = 1'b1;
					ram_data_next[0] = 18'd0;
					ram_addr_next = 20'd0;
					bus_busy_next = 1'b1;
					int_case_next = 3'd1;
					int_trig_addr_next = 20'd0;
//					int_cntr_next[0] = {cfg_data[7:0], 10'd0};
					int_cntr_next[0] = 20'd262143;
//					int_cntr_next[1] = {cfg_data[15:8], 10'd0};
					int_cntr_next[1] = 20'd5000;
				end

			end

			// write zeros
			1:
			begin
				ram_wren_next[0] = 1'b1;
				ram_data_next[0] = 18'd2;
				if(&ram_addr_reg)
				begin
					int_case_next = 3'd2;
				end
				else
				begin
					ram_addr_next = ram_addr_reg + 20'd1;
				end
			end

			// sample recording
			2:
			begin
				if (frame)
				begin
					osc_data_next = osc_data;
					ram_addr_next = ram_addr_reg + 20'd1;
					ram_wren_next[0] = 1'b1;
					ram_data_next[0] = {osc_data[15:8], 1'b0, osc_data[7:0], 1'b0};
		
					int_case_next = 3'd3;

					if (|int_cntr_reg[1])
					begin
						int_cntr_next[0] = int_cntr_reg[0] - 20'd1;
						int_cntr_next[1] = int_cntr_reg[1] - 20'd1;
					end
					else if (int_trig_reg)
					begin
						if (|int_cntr_reg[0])
						begin
							int_cntr_next[0] = int_cntr_reg[0] - 20'd1;
						end
					end
					else if (trg_flag)
					begin
						int_trig_next = 1'b1;
						int_trig_addr_next = ram_addr_reg - 20'd19999;
					end
				end
			end

			3:
			begin
				ram_addr_next = ram_addr_reg + 20'd1;
				ram_wren_next[0] = 1'b1;
				ram_data_next[0] = {osc_data_reg[31:24], 1'b0, osc_data_reg[23:16], 1'b0};
				int_case_next = 3'd4;
			end

			4:
			begin
				ram_addr_next = ram_addr_reg + 20'd1;
				ram_wren_next[0] = 1'b1;
				ram_data_next[0] = {osc_data_reg[47:40], 1'b0, osc_data_reg[39:32], 1'b0};
				int_case_next = 3'd5;
			end

			5:
			begin
				ram_addr_next = ram_addr_reg + 20'd1;
				ram_wren_next[0] = 1'b1;
				ram_data_next[0] = {osc_data_reg[63:56], 1'b0, osc_data_reg[55:48], 1'b0};
				if (|int_cntr_reg[0])
				begin
					int_case_next = 3'd2;
				end
				else
				begin
					int_case_next = 3'd0;
				end
			end

		endcase
	end

	assign bus_miso = bus_miso_reg;
	assign bus_busy = bus_busy_reg;

endmodule
