// -----------------------------------------------------------------------------
// Copyright (c) 2013, ON Semiconductor.
// -----------------------------------------------------------------------------
// FILE NAME     : dig_owi_fsm.v
// TYPE          : RTL
// AUTHOR        : Stephanie cambounet
// AUTHORS EMAIL : Stephanie.cambounet@onsemi.com
// -----------------------------------------------------------------------------
// RELEASE HISTORY
// VERSION DATE        AUTHOR                DESCRIPTION
//  1.0    2013-09-16  Stephanie cambounet   Initial version
// -----------------------------------------------------------------------------
// KEYWORDS : 
// -----------------------------------------------------------------------------
// PURPOSE : 
// -----------------------------------------------------------------------------

module dig_owi_fsm (
input             reset_b,
input             SDA_in,
input             rx_clk,
input             tx_clk,
input             start_rx,
input [3:0]       bit_cnt,         
input [1:0]       prog_ib_delay,

input           read_data_oca_stat,
input           read_data_ova_stat,
input           read_data_ota_stat,
input           read_data_com_er_stat,
input           read_data_chg_ok_stat,
input  [1:0]    read_data_vin_msb,
input  [5:0]    read_data_vin_lsb,
input  [1:0]    read_data_iin_msb,
input  [5:0]    read_data_iin_lsb,
input  [1:0]    read_data_temp_msb,
input  [5:0]    read_data_temp_lsb,
input  [3:0]    read_data_vth,
input  [2:0]    read_data_vcl,
input  [2:0]    read_data_div2_dly,
input           read_data_clo_dis,
input  [3:0]    read_data_n_cli,
input           read_data_mode_m,
input  [1:0]    read_data_ib_dly,
input           read_data_pwr_ok,
input           read_data_tsd_int,
input           read_data_com_er_int,
input           read_data_ota_int,
input           read_data_ova_int,
input           read_data_oca_int,
input  [5:0]    read_data_rev_id,
input           owi_VIT_done_rstb, 
input           owi_VI_done_rstb,
input           adc_data_rdy,  

///???input             vddowi_det,

output            SDA_out,
output reg        com_er,
output reg        start_tx,
output reg        ib_delay,
output reg        WR,
output reg        RD,
output            rx_tx_clk_en,
output reg [5:0]  cmd,

output  [3:0]    write_data_vth,
output  [2:0]    write_data_vcl,
output           write_data_clo_dis,
output  [2:0]    write_data_div2_dly,
output           write_data_pwr_ok,
output  [1:0]    write_data_ib_dly,
output reg [13:0]   reg_en,
output reg       adc_VIT_req,
output reg       adc_VI_req,
output           adc_data_rdy_fsm  
);

parameter [1:0] SHIFT            = 2'b00;
parameter [1:0] SEND_START_DATA  = 2'b01;
parameter [1:0] SEND_DATA        = 2'b10;
parameter [1:0] SEND_PARITY      = 2'b11;

reg         transmit_error;
reg         parity_error;
reg         byte_to_discard;
reg         adc_data_rdy_reg;

reg [3:0]   byte_cnt;
reg [3:0]   byte_cnt_exp;
reg         read_cmd;
reg         single_byte;
reg         cmd_unknown;

reg [5:0]   cmd_preview;
reg [17:0]  data;
reg [5:0]   read_data;
reg [5:0]   parity_exp;
reg [8:0]   cnt_ib_delay;

reg [1:0]   SelectEmitReg;
reg [9:0]   ReceivedRegister;
reg [8:0]   Synch_ReceivedRegister;
reg [9:0]   EmitReg;
reg [8:0]   max_ibd;

wire        stop_bit;

//------------------------------------------------------------------------------
parameter OFF          = 6'b000001;
parameter CMD          = 6'b000010;
parameter RX_DATA      = 6'b000100;
parameter RX_PARITY    = 6'b001000;
parameter TX_DATA      = 6'b010000;
parameter TX_PARITY    = 6'b100000;

`define s_OFF          state[0]
`define s_CMD          state[1]
`define s_RX_DATA      state[2]
`define s_RX_PARITY    state[3]
`define s_TX_DATA      state[4]
`define s_TX_PARITY    state[5]

`define ns_OFF         next_state[0]
`define ns_CMD         next_state[1]
`define ns_RX_DATA     next_state[2]
`define ns_RX_PARITY   next_state[3]
`define ns_TX_DATA     next_state[4]
`define ns_TX_PARITY   next_state[5]

reg [5:0] state;
reg [5:0] next_state;

//------------------------------------------------------------------------------
// clock request
//------------------------------------------------------------------------------
assign rx_tx_clk_en =  com_er | WR;

//------------------------------------------------------------------------------
// sequencing
//------------------------------------------------------------------------------
assign stop_bit = (bit_cnt == 4'd9);
assign cmd_ready = (bit_cnt == 4'd8);

//------------------------------------------------------------------------------
// data byte counter
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      byte_cnt           <= 4'b0000;
   end
   else if ( start_rx || start_tx ) begin          ///et tx
         byte_cnt <= byte_cnt + 4'b0001;
   end
   else if ( stop_bit ) begin
      if ((ReceivedRegister[8:7] == 2'b00) && (`s_RX_PARITY || `s_RX_DATA)) begin    //case of new message start
         byte_cnt <= 4'b0001;
      end
      else if ((!ReceivedRegister[9] || (`s_CMD && |ReceivedRegister[8:7])) || (`s_RX_PARITY && (ReceivedRegister[8:7] != 2'b10)) || (`s_RX_DATA && (ReceivedRegister[8:7]!= 2'b01))) begin        ///discard_error
         byte_cnt <= byte_cnt - 4'b0001;
      end   
      else if ( `s_CMD && `ns_TX_DATA) begin
         byte_cnt <= 4'b0000;      
      end   
      else if (byte_cnt == byte_cnt_exp) begin
         byte_cnt <= 4'b0000;
      end
    end
end

//------------------------------------------------------------------------------
// SDA Out NMOS driver
//------------------------------------------------------------------------------
assign SDA_out = ~EmitReg[0];

//assign SCL_b = (scan_mode) ? SCL : ~SCL;

//------------------------------------------------------------------------------
// SelectEmitReg
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      SelectEmitReg <= SHIFT;
   end
   else if (`s_CMD && `ns_TX_DATA  && stop_bit ) begin
               SelectEmitReg <= SEND_START_DATA;
   end     
   else if (`s_TX_DATA && `ns_TX_DATA && (cnt_ib_delay == max_ibd)) begin       //stop_bit
               SelectEmitReg <= SEND_DATA;
   end
   else if (`s_TX_DATA && `ns_TX_PARITY && (cnt_ib_delay == max_ibd)) begin
               SelectEmitReg <= SEND_PARITY;
   end
   else 
      SelectEmitReg <= SHIFT;  
end        

//------------------------------------------------------------------------------
// Emit registers
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      EmitReg <= 10'b1111111111;
   end
   else begin
      case(SelectEmitReg)
      SEND_START_DATA   : EmitReg <= {1'b1,2'b00,read_data[5:0],1'b0};
      SEND_DATA         : EmitReg <= {1'b1,2'b01,read_data[5:0],1'b0};
      SEND_PARITY       : EmitReg <= {1'b1,2'b10,parity_exp,1'b0};      
      default           : EmitReg <= {1'b1,EmitReg[9:1]};   //SHIFT
      endcase
   end
end

//------------------------------------------------------------------------------
// Synchro registers
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      Synch_ReceivedRegister <= 9'b000000000;
   end
   else begin
      Synch_ReceivedRegister <= ReceivedRegister[9:1];
   end
end

//------------------------------------------------------------------------------
// received register
//------------------------------------------------------------------------------
always @ (posedge rx_clk or negedge reset_b) begin
   if(!reset_b) begin
      ReceivedRegister <= 10'b0000000000;
   end
   else begin
      ReceivedRegister <= {SDA_in, Synch_ReceivedRegister[8:0]};    ///LSB first
   end
end   

//------------------------------------------------------------------------------
// command
//------------------------------------------------------------------------------
// cmd_preview is cmd sampled after trans bits, it will be erased by next one if byte is not valid
// cmd_preview is used to anticipate new start
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      cmd_preview <= 6'd0;
   end
//   else if (stop_bit && (byte_to_discard || (ReceivedRegister[8:7] != 2'b00) || ~ReceivedRegister[9])) begin         
//      cmd <= 6'd0;
//   end
   else if ( cmd_ready && (ReceivedRegister[9:8] == 2'b00) && (`s_CMD || `s_RX_DATA || `s_RX_PARITY )) begin
      cmd_preview[5:0]  <= ReceivedRegister[7:2];
   end
end   

always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      cmd <= 6'b111111;
   end
   else if (stop_bit && ReceivedRegister[9]) begin         
      cmd <= cmd_preview;
   end
end


//------------------------------------------------------------------------------
// cmd decoder
//------------------------------------------------------------------------------
always @ (*) begin
 case(cmd_preview)
   6'b000000  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd10,1'b1,1'b0,1'b0,14'b000000_01111111 };   ///read status + ADC results
   6'b000001  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd5, 1'b1,1'b0,1'b0,14'b000111_10000000 };   ///read vth/vcl/cmd/sense
   6'b000010  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd6, 1'b0,1'b0,1'b0,14'b000111_10000000 };   ///write vth/vcl/cmd/sense
   6'b000011  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd1, 1'b1,1'b0,1'b0,14'b000000_00000001 };   ///read status
   6'b000100  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd5, 1'b1,1'b0,1'b0,14'b011000_00000000 };   ///read regs
   6'b000101  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd6, 1'b0,1'b0,1'b0,14'b011000_00000000 };   ///write regs
   6'b000110  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd1, 1'b1,1'b0,1'b0,14'b100000_00000000 };   ///read revision
   6'b000111  : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd5, 1'b1,1'b0,1'b0,14'b000000_00011110 };   ///read ADC VI results
   default    : { byte_cnt_exp,read_cmd,single_byte,cmd_unknown,reg_en } = { 4'd0, 1'b0,1'b0,1'b1,14'b000000_00011110 };
 endcase
end
///rev register: address to be confirmed!
      

always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      start_tx <= 1'b0;
   end
   else if ( `ns_OFF ) begin         
      start_tx <= 1'b0;
   end   
   else if ( `s_CMD && `ns_TX_DATA ) begin         
      start_tx <= stop_bit && read_cmd ;
   end
   else if ( `s_TX_DATA || `s_TX_PARITY ) begin         
      start_tx <= ((cnt_ib_delay == max_ibd)  && read_cmd );
   end
end      


//------------------------------------------------------------------------------
// adc_requests
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge owi_VIT_done_rstb) begin
   if(!owi_VIT_done_rstb) begin
      adc_VIT_req <= 1'b0;
   end
   // in case of new message start, RD can occures in another state of CMD 
   else if ( stop_bit && ReceivedRegister[9] && (ReceivedRegister[8:7] == 2'b00) && !transmit_error &&         //valid CMD transmit
            !(`s_TX_DATA || `s_TX_PARITY) && `ns_TX_DATA &&                                                    //end of CMD
            (cmd_preview == 6'd0)) begin                                                                       //ADC command 0
      adc_VIT_req <= 1'b1;                                                                   
   end    
end

always @ (posedge tx_clk or negedge owi_VI_done_rstb) begin
   if(!owi_VI_done_rstb) begin
      adc_VI_req <= 1'b0;
   end  
   // in case of new message start, RD can occures in another state of CMD 
   else if ( stop_bit && ReceivedRegister[9] && (ReceivedRegister[8:7] == 2'b00) && !transmit_error &&         //valid CMD transmit
            !(`s_TX_DATA || `s_TX_PARITY) && `ns_TX_DATA &&                                                    //end of CMD
            (cmd_preview == 6'd7)) begin                                                                       //ADC command 7
      adc_VI_req <= 1'b1;                                                                   
   end    
end

///temporaire
///assign adc_data_rdy_fsm = adc_data_rdy;

assign adc_data_rdy_fsm = ((cmd == 6'd0) || (cmd == 6'd7)) ?  adc_data_rdy_reg | adc_data_rdy : 1'b1;

always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      adc_data_rdy_reg <= 1'b0;
   end   
   else if (start_rx)  begin        //new cmd 
      adc_data_rdy_reg <= 1'b0;
   end  
   else if ((cmd == 6'd0) || (cmd == 6'd7))  begin      
      if ( adc_data_rdy )  begin  
         adc_data_rdy_reg <= 1'b1;
      end
   end
end


//------------------------------------------------------------------------------
// write data
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      data <= 18'd0;
   end
//in case of new message start 
   else if ( stop_bit && (ReceivedRegister[8:7] == 2'b00)) begin  
      data <= 18'd0;
   end   

//data not registered if byte not correct  
   else if (`s_RX_DATA && stop_bit && ReceivedRegister[9] && !byte_to_discard) begin   
      if (byte_cnt == 4'd2) begin
         data[5:0]  <= ReceivedRegister[6:1]; 
      end
      else if (byte_cnt == 4'd3) begin
         data[11:6]  <= ReceivedRegister[6:1]; 
      end
      else if (byte_cnt == 4'd4) begin
         data[17:12]  <= ReceivedRegister[6:1]; 
      end     
//       else if (byte_cnt == 4'd5) begin                   ///pas utile
//          data[23:18]  <= ReceivedRegister[6:1]; 
//       end         
   end
end   

assign write_data_vth      = (cmd == 6'b000010) ? data[3:0]    : 4'b0000;
assign write_data_vcl      = (cmd == 6'b000010) ? data[8:6]    : 3'b000;
assign write_data_clo_dis  = (cmd == 6'b000010) ? data[12]     : 1'b0;
assign write_data_div2_dly = (cmd == 6'b000010) ? data[17:15]  : 3'b000;
assign write_data_pwr_ok   = (cmd == 6'b000101) ? data[1]      : 1'b0;
assign write_data_ib_dly   = (cmd == 6'b000101) ? data[3:2]    : 2'b00;


//------------------------------------------------------------------------------
// read data
//------------------------------------------------------------------------------

always @ (*) begin
//always @ (posedge tx_clk or negedge reset_b) begin
//    if(!reset_b) begin
//       read_data <= 6'd0;
//    end
//    else begin   
    if (!`s_TX_DATA ) begin  
        read_data = 6'b000000;
    end    
    else begin
    if (cmd == 6'b000000 ) begin  ///read status + ADC results
     if ((byte_cnt == 4'd0 && start_tx) || (byte_cnt == 4'd1 && !start_tx)) begin
        read_data = {read_data_oca_stat,read_data_ota_stat,1'b1,read_data_com_er_stat,read_data_ova_stat,read_data_chg_ok_stat} ;
     end
     else if ((byte_cnt == 4'd1 && start_tx) || (byte_cnt == 4'd2 && !start_tx)) begin
        read_data = read_data_vin_lsb ;
     end
     else if ((byte_cnt == 4'd2 && start_tx) || (byte_cnt ==  4'd3 && !start_tx)) begin
        read_data = {4'b0000,read_data_vin_msb} ;
     end
     else if ((byte_cnt ==  4'd3 && start_tx) || (byte_cnt ==  4'd4 && !start_tx)) begin
        read_data = read_data_iin_lsb ;
     end
     else if ((byte_cnt ==  4'd4 && start_tx) || (byte_cnt ==  4'd5 && !start_tx)) begin
        read_data = {4'b0000,read_data_iin_msb} ;
     end
     else if ((byte_cnt ==  4'd5 && start_tx) || (byte_cnt ==  4'd6 && !start_tx)) begin
        read_data = read_data_temp_lsb ;
     end
     else if ((byte_cnt ==  4'd6 && start_tx) || (byte_cnt ==  4'd7 && !start_tx)) begin
        read_data = {4'b0000,read_data_temp_msb} ;
     end
     else if ((byte_cnt ==  4'd7 && start_tx) || (byte_cnt ==  4'd8 && !start_tx)) begin
        read_data = 6'b000000;
     end
     else if ((byte_cnt ==  4'd8 && start_tx) || (byte_cnt ==  4'd9 && !start_tx)) begin
        read_data = 6'b000000;
     end
     else begin
        read_data = 6'b000000;
     end
    end     
    else if (cmd == 6'b000001 ) begin  ///read vth/vcl/cmd/sense
     if ((byte_cnt ==  4'd0 && start_tx) || (byte_cnt ==  4'd1 && !start_tx))  begin
        read_data = {2'b00,read_data_vth};
     end
     else if ((byte_cnt ==  4'd1 && start_tx) || (byte_cnt ==  4'd2 && !start_tx)) begin
        read_data = {3'b000,read_data_vcl};
     end
     else if ((byte_cnt ==  4'd2 && start_tx) || (byte_cnt ==  4'd3 && !start_tx)) begin
        read_data = {read_data_div2_dly,2'b00,read_data_clo_dis} ;
     end
     else if ((byte_cnt ==  4'd3 && start_tx) || (byte_cnt ==  4'd4 && !start_tx)) begin
        read_data = {read_data_n_cli,1'b0,read_data_mode_m} ;
     end
     else begin
        read_data = 6'b000000;
     end
    end
    else if (cmd == 6'b000011 ) begin  ///read status
     if ((byte_cnt ==  4'd0 && start_tx) || (byte_cnt ==  4'd1 && !start_tx)) begin
        read_data = {read_data_oca_stat,read_data_ota_stat,1'b1,read_data_com_er_stat,read_data_ova_stat,read_data_chg_ok_stat};
     end
     else begin
        read_data = 6'b000000;
     end
    end
    else if (cmd == 6'b000100 ) begin  ///read extended regs
     if ((byte_cnt == 0 && start_tx) || (byte_cnt == 1 && !start_tx)) begin
        read_data = {2'b00,read_data_ib_dly,read_data_pwr_ok,1'b1};
     end
     else if ((byte_cnt ==  4'd1 && start_tx) || (byte_cnt ==  4'd2 && !start_tx)) begin
        read_data = 6'b001111;
     end
     else if ((byte_cnt ==  4'd2 && start_tx) || (byte_cnt ==  4'd3 && !start_tx)) begin
        read_data = {1'b0,read_data_tsd_int,read_data_com_er_int,read_data_ota_int,read_data_ova_int,read_data_oca_int} ;
     end
     else if ((byte_cnt ==  4'd3 && start_tx) || (byte_cnt ==  4'd4 && !start_tx)) begin
        read_data = {6'b000101} ;
     end
     else begin
        read_data = 6'b000000;
     end
    end
    else if (cmd == 6'b000110 ) begin  ///read revision
     if ((byte_cnt ==  4'd0 && start_tx) || (byte_cnt ==  4'd1 && !start_tx)) begin
        read_data = read_data_rev_id;
     end
     else begin
        read_data = 6'b000000;
     end
    end
    else if (cmd == 6'b000111 ) begin  ///read ADC VI results
     if ((byte_cnt ==  4'd0 && start_tx) || (byte_cnt ==  4'd1 && !start_tx)) begin
        read_data = read_data_vin_lsb ;
     end
     else if ((byte_cnt ==  4'd1 && start_tx) || (byte_cnt ==  4'd2 && !start_tx)) begin
        read_data = {4'b0000,read_data_vin_msb} ;
     end
     else if ((byte_cnt ==  4'd2 && start_tx) || (byte_cnt ==  4'd3 && !start_tx)) begin
        read_data = read_data_iin_lsb ;
     end
     else if ((byte_cnt ==  4'd3 && start_tx) || (byte_cnt ==  4'd4 && !start_tx)) begin
        read_data = {4'b0000,read_data_iin_msb} ;
     end
     else begin
        read_data = 6'b000000;
     end
    end
    else begin
        read_data = 6'b000000;
    end
    end 
end    

//------------------------------------------------------------------------------
// calculated parity
//------------------------------------------------------------------------------
// registers are shared for RX and TX
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      parity_exp <= 6'd0;
   end
   else if ((`s_RX_PARITY && stop_bit && !byte_to_discard && (ReceivedRegister[8:7] != 2'b00)) ||   //end of RX write transmission
           (`s_CMD && `ns_TX_DATA && stop_bit && !byte_to_discard) ||                              //end of CMD before read   
           (`ns_OFF)) begin                                                                        //end of TX tramsission       
      parity_exp <= 6'd0;  
   end    
   else if (`s_CMD || `s_RX_DATA) begin
      if ( stop_bit && ReceivedRegister[9] && !byte_to_discard) begin       //parity is not calculated on byte to discard 
            if (ReceivedRegister[8:7] == 2'b00) begin                      //case of new message start
               parity_exp[5:0]  <= ReceivedRegister[6:1];
            end
            else begin   
               parity_exp[5:0]  <= parity_exp[5:0] ^ ReceivedRegister[6:1];
            end   
      end
   end 
   else if (`s_RX_PARITY && stop_bit && ReceivedRegister[9] && !byte_to_discard && (ReceivedRegister[8:7]== 2'b00)) begin   //case of new message start
   parity_exp[5:0]  <= ReceivedRegister[6:1];
   end     
   else if (`s_TX_DATA) begin
       if ( stop_bit ) begin        
         parity_exp[5:0]  <= parity_exp[5:0] ^ read_data[5:0];
       end
   end        
end   

//------------------------------------------------------------------------------
// parity error
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      parity_error <= 1'b0;
   end
   else if ( stop_bit ) begin
      parity_error <= 1'b0;
   end   
   else if (`s_RX_PARITY && cmd_ready && (ReceivedRegister[9:8] == 2'b10)) begin
      parity_error <= (ReceivedRegister[7:2] != parity_exp);
   end
end

//------------------------------------------------------------------------------
// com_er
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      com_er <= 1'b0;
   end
   else begin     
      com_er <= stop_bit & (~ReceivedRegister[9] | (transmit_error && ReceivedRegister[9]) | (parity_error && ReceivedRegister[9]));        
   end
end     
/// il faut un coup de tx_clk supplementaire...pour n'avoir qu'un pulse


always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      transmit_error <= 1'b0;
   end
   else if ( stop_bit ) begin
      transmit_error <= 1'b0;
   end   
   else if ( cmd_ready ) begin     
      transmit_error <= (`s_CMD &&        ((ReceivedRegister[9:8] == 2'b10) || (ReceivedRegister[9:8] == 2'b01))) ||        //^transmit
                        (`s_RX_DATA &&    ((ReceivedRegister[9:8] == 2'b00) || (ReceivedRegister[9:8] == 2'b10))) ||
                        (`s_RX_PARITY &&  ((ReceivedRegister[9:8] == 2'b00) || (ReceivedRegister[9:8] == 2'b01)));
   end
end                                              

always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      byte_to_discard <= 1'b0;  
   end
   else if ( stop_bit ) begin
      byte_to_discard <= 1'b0;  
   end   
   else if ( cmd_ready ) begin     
      byte_to_discard <= (`s_CMD &&        (|ReceivedRegister[9:8])) ||     
                         (`s_RX_DATA &&    (ReceivedRegister[9:8] == 2'b10)) ||
                         (`s_RX_PARITY &&  (ReceivedRegister[9:8] == 2'b01));
   end
end         
   
//------------------------------------------------------------------------------
// WR signal
//------------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
       WR  <= 1'b0;
   end
   else begin
       WR  <= stop_bit & ReceivedRegister[9] & ~transmit_error & ~parity_error & `s_RX_PARITY;
   end    
end

//------------------------------------------------------------------------------
// RD signal
//------------------------------------------------------------------------------

always @ (posedge tx_clk or negedge reset_b) begin
   if(!reset_b) begin
      RD  <= 1'b0;
   end
   else begin
      RD  <= cmd_ready & `ns_TX_PARITY;
   end    
end

// -----------------------------------------------------------------------------
// inter byte delay 
// -----------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if (!reset_b) begin
      ib_delay <= 1'b0;
   end
   else if ( cnt_ib_delay == max_ibd ) begin
      ib_delay <= 1'b0;
   end
   else if ( stop_bit && `s_TX_DATA && (cmd !=6'b000110) && (cmd != 6'b000011)) begin
      ib_delay <= 1'b1;
   end   
end
 
always @ (posedge tx_clk or negedge reset_b) begin
   if (!reset_b) begin
      cnt_ib_delay <= 9'd0;
   end
   else if ( ib_delay ) begin
      if (cnt_ib_delay == max_ibd ) begin
         cnt_ib_delay <= 9'd0;
      end
      else begin
         cnt_ib_delay <= cnt_ib_delay + 9'd1;
      end
   end
end

 always @ (*) begin
    case (prog_ib_delay) 
         2'b00 : max_ibd = 9'd3;            //4 bit cycles delay
         2'b01 : max_ibd = 9'd115;          //1ms + 4 bit cycles delay
         2'b10 : max_ibd = 9'd230;          //2ms + 4 bit cycles delay
         2'b11 : max_ibd = 9'd460;          //4ms + 4 bit cycles delay
   endcase
end

// -----------------------------------------------------------------------------
// OWI FSM 
// -----------------------------------------------------------------------------
always @ (posedge tx_clk or negedge reset_b) begin
   if (!reset_b)
      state <= OFF;
   else
      state <= next_state;
end


always @ (*) begin
   
   next_state = state;
   
   case (state)

   // OFF
   // --------------------------------------------------------------------------
   OFF : begin 
      if ( start_rx ) begin
         next_state = CMD;
      end
   end

   // CMD
   // --------------------------------------------------------------------------
   CMD : begin 
      if ( stop_bit ) begin
         if (!ReceivedRegister[9] || single_byte || |ReceivedRegister[8:7]  || cmd_unknown ) begin
            next_state = OFF;
         end
         else if ( read_cmd ) begin
            next_state = TX_DATA;
         end
         else begin
            next_state = RX_DATA;      
         end
      end 
   end

   // RX_DATA
   // --------------------------------------------------------------------------
   RX_DATA : begin 
      if ( stop_bit ) begin     
         if ( !ReceivedRegister[9] || (ReceivedRegister[8:7] == 2'b10)) begin    //discard byte
            next_state = RX_DATA;
         end   
         else if (ReceivedRegister[8:7] == 2'b00) begin                          //new message start
             if ( single_byte ) begin
               next_state = OFF;            
            end
            else if ( read_cmd ) begin
               next_state = TX_DATA;                        
            end
            else begin
               next_state = RX_DATA; 
            end 
         end                           
         else if ( byte_cnt < byte_cnt_exp - 4'd1 ) begin     
            next_state = RX_DATA;           
         end  
         else begin
            next_state = RX_PARITY;  
         end     
      end
   end   

   // RX_PARITY
   // --------------------------------------------------------------------------
   RX_PARITY : begin 
      if ( stop_bit ) begin
         if ( !ReceivedRegister[9] || (ReceivedRegister[8:7] == 2'b01)) begin    //discard byte
            next_state = RX_PARITY;
         end   
         else if (ReceivedRegister[8:7] == 2'b00) begin                          //new message start
            if ( single_byte ) begin
               next_state = OFF;            
            end
            else if ( read_cmd ) begin
               next_state = TX_DATA;                        
            end
            else begin
               next_state = RX_DATA;                        
            end
         end  
         else begin                                                              //end of the message
               next_state = OFF;                        
         end         
      end      
   end   

   // TX_DATA
   // --------------------------------------------------------------------------
   TX_DATA : begin               
      if ( stop_bit ) begin
         if ( byte_cnt == byte_cnt_exp) begin     
            next_state = OFF;
         end
      end   
      else if (cnt_ib_delay == max_ibd ) begin 
         if (byte_cnt < byte_cnt_exp - 4'd1 ) begin     
            next_state = TX_DATA;
         end            
         else begin
            next_state = TX_PARITY;
         end  
      end                  
   end

   // TX_PARITY
   // --------------------------------------------------------------------------
   TX_PARITY : begin 
      if ( stop_bit ) begin
         next_state = OFF;
      end
   end

  default : begin
     next_state = OFF;
  end

  endcase
end

`undef s_OFF              
`undef s_CMD        
`undef s_RX_DATA       
`undef s_RX_PARITY    
`undef s_TX_PARITY     
`undef s_TX_DATA    

`undef ns_OFF              
`undef ns_CMD        
`undef ns_RX_DATA       
`undef ns_RX_PARITY    
`undef ns_TX_PARITY     
`undef ns_TX_DATA  

endmodule

