module serial_bus_state(
input ref_clk,
input reset,
input sclk,
input sdout,
input sen,
output sdin,
output reg [7:0] ADDR,
output reg [7:0] DOUT,
input [7:0] DIN,
output rdy
);
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_WAIT_ADDR_CLK_HIGH = 3'd1,
STATE_WAIT_ADDR_CLK_LOW = 3'd2,
STATE_WAIT_WR_CLK_HIGH = 3'd3,
STATE_WAIT_WR_CLK_LOW = 3'd4,
STATE_WAIT_RD_CLK_HIGH = 3'd5,
STATE_WAIT_RD_CLK_LOW = 3'd6,
STATE_WR_READY = 3'd7;
reg [2:0] NEXT_STATE;
reg [7:0] NEXT_BIT_MASK;
reg [7:0] NEXT_ADDR;
reg [7:0] NEXT_DOUT;
reg [2:0] CUR_STATE;
reg [7:0] CUR_BIT_MASK;
always @(posedge ref_clk)
begin
if(reset | sen)
begin
CUR_STATE <= STATE_IDLE;
CUR_BIT_MASK <= 8'd1;
ADDR <= 8'd0;
DOUT <= 8'd0;
end
else
begin
CUR_STATE <= NEXT_STATE;
CUR_BIT_MASK <= NEXT_BIT_MASK;
ADDR <= NEXT_ADDR;
DOUT <= NEXT_DOUT;
end
end
// -------------------------------
always @(*)
begin
NEXT_STATE = CUR_STATE;
NEXT_ADDR = ADDR;
NEXT_DOUT = DOUT;
NEXT_BIT_MASK = CUR_BIT_MASK;
case(CUR_STATE)
STATE_IDLE :
begin
if(~sclk)
begin
NEXT_BIT_MASK = 8'd1;
NEXT_ADDR = 8'd0;
NEXT_STATE = STATE_WAIT_ADDR_CLK_HIGH;
end
end
// *******************
STATE_WAIT_ADDR_CLK_HIGH :
begin
if(sclk)
begin
NEXT_ADDR = {ADDR[6:0], sdout};
NEXT_STATE = STATE_WAIT_ADDR_CLK_LOW;
end
end
// *******************
STATE_WAIT_ADDR_CLK_LOW :
begin
if(~sclk)
begin
if(CUR_BIT_MASK[7])
begin
NEXT_BIT_MASK = 8'd1;
if(ADDR[7])
NEXT_STATE = STATE_WAIT_RD_CLK_HIGH;
else
begin
NEXT_DOUT = 8'd0;
NEXT_STATE = STATE_WAIT_WR_CLK_HIGH;
end
end
else
begin
NEXT_BIT_MASK = {CUR_BIT_MASK[6:0], 1'b0};
NEXT_STATE = STATE_WAIT_ADDR_CLK_HIGH;
end
end
end
// *******************
STATE_WAIT_WR_CLK_HIGH :
begin
if(sclk)
begin
NEXT_DOUT = {DOUT[6:0], sdout};
NEXT_STATE = STATE_WAIT_WR_CLK_LOW;
end
end
// *******************
STATE_WAIT_WR_CLK_LOW :
begin
if(~sclk)
begin
if(CUR_BIT_MASK[7])
NEXT_STATE = STATE_WR_READY;
else
begin
NEXT_BIT_MASK = {CUR_BIT_MASK[6:0], 1'b0};
NEXT_STATE = STATE_WAIT_WR_CLK_HIGH;
end
end
end
// *******************
STATE_WAIT_RD_CLK_HIGH :
begin
if(sclk)
NEXT_STATE = STATE_WAIT_RD_CLK_LOW;
end
// *******************
STATE_WAIT_RD_CLK_LOW :
begin
if(~sclk)
begin
if(CUR_BIT_MASK[7])
NEXT_STATE = STATE_IDLE;
else
begin
NEXT_BIT_MASK = {CUR_BIT_MASK[6:0], 1'b0};
NEXT_STATE = STATE_WAIT_RD_CLK_HIGH;
end
end
end
// *******************
STATE_WR_READY :
begin
NEXT_STATE = STATE_IDLE;
end
endcase
end
// -------------------------------
assign sdin = ((CUR_BIT_MASK & DIN) == 0) ? 1'b0 : 1'b1;
assign rdy = (CUR_STATE == STATE_WR_READY);
endmodule