module mio_regs #(parameter N        = 8,        // number of I/O pins  
		  parameter AW       = 32,       // address width
		  parameter PW       = 104,      // packet width
		  parameter DEF_CFG  = 18'h1070, // default config   
		  parameter DEF_CLK  = 7         // clock divider   
		  )
   (
    // clk,reset
    input 	    clk,
    input 	    nreset,
    // register access interface
    input 	    access_in, // incoming access
    input [PW-1:0]  packet_in, // incoming packet
    output 	    wait_out, 
    output 	    access_out, // outgoing read packet
    output [PW-1:0] packet_out, // outgoing read packet
    input 	    wait_in,
    // config outputs
    output 	    tx_en, // enable tx
    output 	    rx_en, // enable rx
    output 	    ddr_mode, // ddr mode for mio
    output 	    emode, // epiphany packet mode
    output 	    amode, // mio packet mode
    output 	    dmode, // mio packet mode
    output [1:0]    datamode, // mio datasize
    output [1:0]    iowidth, // mio io width
    output 	    lsbfirst, // lsb shift first
    output 	    framepol, // framepolarity (0=actrive high)   
    output [4:0]    ctrlmode, // emode ctrlmode
    output [AW-1:0] dstaddr, // destination address for RX dmode
    output 	    clkchange, // indicates a clock change   
    output [7:0]    clkdiv, // mio clk clock setting
    output [15:0]   clkphase0, // [7:0]=rising,[15:8]=falling
    output [15:0]   clkphase1, // [7:0]=rising,[15:8]=falling
    // status inputs
    input 	    tx_full, //tx fifo is full (should not happen!)  
    input 	    tx_prog_full, //tx fifo is nearing full
    input 	    tx_empty, //tx fifo is empty
    input 	    rx_full, //rx fifo is full (should not happen!)  
    input 	    rx_prog_full, //rx fifo is nearing full
    input 	    rx_empty     //rx fifo is empty
    );
   
   localparam  DEF_RISE0 = 0;                      // 0 degrees
   localparam  DEF_FALL0 = ((DEF_CLK+8'd1)>>8'd1); // 180 degrees
   localparam  DEF_RISE1 = ((DEF_CLK+8'd1)>>8'd2); // 90 degrees
   localparam  DEF_FALL1 = ((DEF_CLK+8'd1)>>8'd2)+
			   ((DEF_CLK+8'd1)>>8'd1); // 270 degrees

   //##############
   //# LOCAL WIRES
   //##############

   reg [20:0] 	    config_reg;   
   reg [15:0] 	    status_reg;
   reg [31:0] 	    clkdiv_reg;
   reg [63:0] 	    addr_reg;
   reg [31:0] 	    clkphase_reg;
   wire [7:0] 	    status_in;
   wire 	    reg_write;
   wire 	    config_write;
   wire 	    status_write;
   wire 	    clkdiv_write;
   wire 	    clkphase_write;
   wire 	    idelay_write;
   wire 	    odelay_write;
   wire 	    addr0_write;
   wire 	    addr1_write;
   
   /*AUTOWIRE*/
   // Beginning of automatic wires (for undeclared instantiated-module outputs)
   wire [4:0]		ctrlmode_in;		// From p2e of packet2emesh.v
   wire [AW-1:0]	data_in;		// From p2e of packet2emesh.v
   wire [1:0]		datamode_in;		// From p2e of packet2emesh.v
   wire [AW-1:0]	dstaddr_in;		// From p2e of packet2emesh.v
   wire [AW-1:0]	srcaddr_in;		// From p2e of packet2emesh.v
   wire			write_in;		// From p2e of packet2emesh.v
   // End of automatics

   //#####################################
   //# DECODE
   //#####################################
   
   packet2emesh #(.AW(AW),
		  .PW(PW))
   p2e (/*AUTOINST*/
	// Outputs
	.write_in			(write_in),
	.datamode_in			(datamode_in[1:0]),
	.ctrlmode_in			(ctrlmode_in[4:0]),
	.dstaddr_in			(dstaddr_in[AW-1:0]),
	.srcaddr_in			(srcaddr_in[AW-1:0]),
	.data_in			(data_in[AW-1:0]),
	// Inputs
	.packet_in			(packet_in[PW-1:0]));

   assign reg_write      = write_in & access_in;
   assign config_write   = reg_write & (dstaddr_in[5:2]==`MIO_CONFIG);
   assign status_write   = reg_write & (dstaddr_in[5:2]==`MIO_STATUS);
   assign clkdiv_write   = reg_write & (dstaddr_in[5:2]==`MIO_CLKDIV);
   assign clkphase_write = reg_write & (dstaddr_in[5:2]==`MIO_CLKPHASE);
   assign idelay_write   = reg_write & (dstaddr_in[5:2]==`MIO_IDELAY);
   assign odelay_write   = reg_write & (dstaddr_in[5:2]==`MIO_ODELAY);
   assign addr0_write    = reg_write & (dstaddr_in[5:2]==`MIO_ADDR0);
   assign addr1_write    = reg_write & (dstaddr_in[5:2]==`MIO_ADDR1);

   assign clkchange = clkdiv_write | clkphase_write;

   //################################
   //# CONFIG
   //################################ 

   always @ (posedge clk or negedge nreset)
     if(!nreset)
       begin
	  config_reg[20:0] <= DEF_CFG;
       end
     else if(config_write)
       config_reg[20:0] <= data_in[20:0];

   assign tx_en         = ~config_reg[0];         // tx disable
   assign rx_en         = ~config_reg[1];         // rx disable
   assign emode         = config_reg[3:2]==2'b00; // emesh packets
   assign dmode         = config_reg[3:2]==2'b01; // data mode (streaming)
   assign amode         = config_reg[3:2]==2'b10; // auto address mode
   assign iowidth[1:0]  = config_reg[5:4];        // iowidth(or 8,16,32,64 pins)
   assign datamode[1:0] = config_reg[7:6];        // rx datamode(8,16,32,64)
   assign ddr_mode      = config_reg[12];         // dual data rate mode   
   assign lsbfirst      = config_reg[13];         // lsb-first transmit
   assign framepol      = config_reg[14];         // frame polarity
   assign ctrlmode[4:0] = config_reg[20:16];      // ctrlmode
  
   //###############################
   //# STATUS
   //################################ 
   assign status_in[7:0] = {2'b0,       //7:6
			   tx_full,     //5			   
			   tx_prog_full,//4
			   tx_empty,    //3
			   rx_full,     //2	 		   
			   rx_prog_full,//1
			   rx_empty     //0
			   };
   
   always @ (posedge clk or negedge nreset)
     if(!nreset)
       status_reg[15:0] <= 'b0;   
     else if(status_write)
       status_reg[15:0] <= data_in[7:0];
     else
       status_reg[15:0] <= {(status_reg[15:8] | status_in[7:0]), // sticky bits
			   status_in[7:0]};                     // immediate bits

   //###############################
   //# CLKDIV
   //################################ 
   always @ (posedge clk or negedge nreset)
     if(!nreset)
       clkdiv_reg[7:0] <= DEF_CLK;   
     else if(clkdiv_write)
       clkdiv_reg[7:0] <= data_in[7:0];

   assign clkdiv[7:0] = clkdiv_reg[7:0];

   //###############################
   //# CLKPHASE
   //################################ 
   always @ (posedge clk or negedge nreset)
     if(!nreset)
       begin
	  clkphase_reg[7:0]   <= DEF_RISE0;
	  clkphase_reg[15:8]  <= DEF_FALL0;
	  clkphase_reg[23:16] <= DEF_RISE1;
	  clkphase_reg[31:24] <= DEF_FALL1;	  
       end
     else if(clkphase_write)
       clkphase_reg[31:0] <= data_in[31:0];

   assign clkphase0[15:0] = clkphase_reg[15:0];
   assign clkphase1[15:0] = clkphase_reg[31:16];
     
   //###############################
   //# RX DESTINATION ADDR ("AMODE")
   //################################ 
   always @ (posedge clk)
     if(addr0_write)
       addr_reg[31:0]  <= data_in[31:0];
     else if(addr1_write)
       addr_reg[63:32] <= data_in[31:0];
   
   assign dstaddr[AW-1:0] = addr_reg[AW-1:0];

   //###############################
   //# READBACK
   //################################ 
   assign access_out ='b0;
   assign wait_out   ='b0;
   assign packet_out ='b0;

endmodule