module dbsm
  (input clk,
   input reset,
   input clear,
   
   output write_ok,
   output write_ptr,
   input write_done,

   output read_ok,
   output read_ptr,
   input read_done,

   output access_ok,
   output access_ptr,
   input access_done,
   input access_skip_read
   );

   localparam PORT_WAIT_0 = 0;
   localparam PORT_USE_0 = 1;
   localparam PORT_WAIT_1 = 2;
   localparam PORT_USE_1 = 3;

   reg [1:0] write_port_state, access_port_state, read_port_state;

   localparam BUFF_WRITABLE = 0;
   localparam BUFF_ACCESSIBLE = 1;
   localparam BUFF_READABLE = 2;
   localparam BUFF_ERROR = 3;

   wire [1:0] buff_state[0:1];
   
   always @(posedge clk)
     if(reset | clear)
       write_port_state <= PORT_WAIT_0;
     else
       case(write_port_state)
	 PORT_WAIT_0 :
	   if(buff_state[0]==BUFF_WRITABLE)
	     write_port_state <= PORT_USE_0;
	 PORT_USE_0 :
	   if(write_done)
	     write_port_state <= PORT_WAIT_1;
	 PORT_WAIT_1 :
	   if(buff_state[1]==BUFF_WRITABLE)
	     write_port_state <= PORT_USE_1;
	 PORT_USE_1 :
	   if(write_done)
	     write_port_state <= PORT_WAIT_0;
       endcase // case (write_port_state)

   assign write_ok = (write_port_state == PORT_USE_0) | (write_port_state == PORT_USE_1);
   assign write_ptr = (write_port_state == PORT_USE_1);
   
   always @(posedge clk)
     if(reset | clear)
       access_port_state <= PORT_WAIT_0;
     else
       case(access_port_state)
	 PORT_WAIT_0 :
	   if(buff_state[0]==BUFF_ACCESSIBLE)
	     access_port_state <= PORT_USE_0;
	 PORT_USE_0 :
	   if(access_done)
	     access_port_state <= PORT_WAIT_1;
	 PORT_WAIT_1 :
	   if(buff_state[1]==BUFF_ACCESSIBLE)
	     access_port_state <= PORT_USE_1;
	 PORT_USE_1 :
	   if(access_done)
	     access_port_state <= PORT_WAIT_0;
       endcase // case (access_port_state)
   
   assign access_ok = (access_port_state == PORT_USE_0) | (access_port_state == PORT_USE_1);
   assign access_ptr = (access_port_state == PORT_USE_1);

   always @(posedge clk)
     if(reset | clear)
       read_port_state <= PORT_WAIT_0;
     else
       case(read_port_state)
	 PORT_WAIT_0 :
	   if(buff_state[0]==BUFF_READABLE)
	     read_port_state <= PORT_USE_0;
	 PORT_USE_0 :
	   if(read_done)
	     read_port_state <= PORT_WAIT_1;
	 PORT_WAIT_1 :
	   if(buff_state[1]==BUFF_READABLE)
	     read_port_state <= PORT_USE_1;
	 PORT_USE_1 :
	   if(read_done)
	     read_port_state <= PORT_WAIT_0;
       endcase // case (read_port_state)
   
   assign read_ok = (read_port_state == PORT_USE_0) | (read_port_state == PORT_USE_1);
   assign read_ptr = (read_port_state == PORT_USE_1);

   buff_sm #(.PORT_USE_FLAG(PORT_USE_0)) buff0_sm
     (.clk(clk), .reset(reset), .clear(clear),
      .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done),
      .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state),
      .buff_state(buff_state[0]));
   
   buff_sm #(.PORT_USE_FLAG(PORT_USE_1)) buff1_sm
     (.clk(clk), .reset(reset), .clear(clear),
      .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done),
      .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state),
      .buff_state(buff_state[1]));
   
endmodule // dbsm