module mactable_dpcam #(
	parameter ADDR_WIDTH = 4,
	parameter KEY_WIDTH = 4,
	parameter DATA_WIDTH = 4,
	parameter RAM_STYLE_DATA = "block",
	parameter CONFIG_WIDTH = ADDR_WIDTH+DATA_WIDTH+KEY_WIDTH,
	parameter REQUEST_WIDTH = KEY_WIDTH*2,
	parameter RESPONSE_WIDTH = (ADDR_WIDTH+DATA_WIDTH)*2
)
(
	input wire aclk,
	input wire aresetn,
	input wire [CONFIG_WIDTH-1:0]s_axis_config_tdata,
	input wire s_axis_config_tuser,
	input wire s_axis_config_tvalid,
	/* Request */
	input wire [REQUEST_WIDTH-1:0]s_axis_request_tdata,
	input wire s_axis_request_tvalid,
	output wire s_axis_request_tready,
	/* Response */
	output wire [RESPONSE_WIDTH-1:0]m_axis_response_tdata,
	output wire [1:0]m_axis_response_tuser,
	output wire m_axis_response_tvalid	
);

wire [ADDR_WIDTH-1:0]set_addr; 
wire [DATA_WIDTH-1:0]set_data;
wire [KEY_WIDTH-1:0]set_key;
wire set_clr;
wire set_valid;

wire [KEY_WIDTH-1:0]req_key[1:0];
wire req_valid;
wire req_ready;

reg [ADDR_WIDTH-1:0]res_addr[1:0];
wire [DATA_WIDTH-1:0]res_data[1:0];
reg res_valid;
reg res_null[1:0];

reg line_valid;
wire [2**ADDR_WIDTH-1:0]line_match[1:0];
wire [ADDR_WIDTH-1:0]enc_addr[1:0];
wire enc_valid;
wire enc_null[1:0];

assign {set_key,set_data,set_addr} = s_axis_config_tdata; 
assign set_clr = s_axis_config_tuser;
assign set_valid = s_axis_config_tvalid;

assign {req_key[1],req_key[0]} = s_axis_request_tdata;
assign req_valid = s_axis_request_tvalid & s_axis_request_tready;
assign s_axis_request_tready = req_ready;

assign m_axis_response_tdata = {{res_data[1],res_addr[1]},{res_data[0],res_addr[0]}};
assign m_axis_response_tuser = {res_null[1],res_null[0]};
assign m_axis_response_tvalid = res_valid;

assign req_ready = (aresetn == 1'b0) ? 1'b0 : ~(line_valid | enc_valid | res_valid);

always @(posedge aclk) begin
	if (aresetn == 1'b0) begin
		line_valid <= 1'b0;
		res_addr[0] <= 0;
		res_addr[1] <= 0;
		res_valid <= 1'b0;
		res_null[0] <= 1'b0;
		res_null[1] <= 1'b0;
	end else begin
		line_valid <= req_valid;
		res_addr[0] <= enc_addr[0];
		res_addr[1] <= enc_addr[1];
		res_valid <= enc_valid;
		res_null[0] <= enc_null[0];
		res_null[1] <= enc_null[1];
	end
end

mactable_dpcam_line_array #(
	.ADDR_WIDTH(ADDR_WIDTH),
	.KEY_WIDTH(KEY_WIDTH)
) mactable_dpcam_line_array_inst (
	.clk(aclk),
	.rst(~aresetn),
	.set_addr(set_addr),
	.set_key(set_key),
	.set_clr(set_clr),
	.set_valid(set_valid),
	.req_key0(req_key[0]),
	.req_key1(req_key[1]),
	.req_valid(req_valid & req_ready),
	.line_match0(line_match[0]),
	.line_match1(line_match[1])
);

mactable_dpcam_line_encoder #(
	.ADDR_WIDTH(ADDR_WIDTH)
) mactable_dpcam_line_encoder0_inst (
	.clk(aclk),
	.rst(~aresetn),
	.line_match(line_match[0]),
	.line_valid(line_valid),
	.addr(enc_addr[0]),
	.addr_valid(enc_valid),
	.addr_null(enc_null[0])
);

mactable_dpcam_line_encoder #(
	.ADDR_WIDTH(ADDR_WIDTH)
) mactable_dpcam_line_encoder1_inst (
	.clk(aclk),
	.rst(~aresetn),
	.line_match(line_match[1]),
	.line_valid(line_valid),
	.addr(enc_addr[1]),
	.addr_valid(),
	.addr_null(enc_null[1])
);

mactable_dpcam_dpram #(
	.ADDR_WIDTH(ADDR_WIDTH),
	.DATA_WIDTH(DATA_WIDTH),
	.RAM_STYLE(RAM_STYLE_DATA)
) mactable_dpcam_dpram_inst (
	.clk(aclk),
	.dina(set_data),
	.addra(set_valid ? set_addr : enc_addr[0]),
	.addrb(enc_addr[1]),
	.wea(set_valid),
	.douta(res_data[0]),
	.doutb(res_data[1])
);

endmodule