📄 pci_spoci_ctrl.v
字号:
if (clk_gen_cnt == 'h0)
begin
scl_oe = 1'b1 ;
scl_oe_en = 1'b1 ;
end
// after half of clock low time, disable the sda driver
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
end
// after clock low time, disable the scl driver - generate low to high transition on the scl line
if (clk_gen_cnt == (period_cnt >> 1))
begin
scl_oe = 1'b0 ;
scl_oe_en = 1'b1 ;
end
// after 1/2 clock high time, report ack or nack condition, depending on the sda input state
if (clk_gen_cnt == ((period_cnt >> 1) + (period_cnt >> 2)) )
begin
ack_rec = ~sda_i_reg ;
nack_rec = sda_i_reg ;
end
// after clock period time expires, check what to do next
if (clk_gen_cnt == period_cnt)
begin
clk_gen_cnt_clr = 1'b1 ;
if (send_bit)
tx_rx_next_state = tx_rx_send_bits ;
else if (rec_bit)
tx_rx_next_state = tx_rx_rec_bits ;
else if (send_stop)
tx_rx_next_state = tx_rx_stop ;
else if (send_start)
tx_rx_next_state = tx_rx_restart ;
else
begin
// this should never happen
tx_rx_next_state = tx_rx_idle ;
end
end
end
tx_rx_send_nack:
begin
clk_gen_cnt_en = 1'b1 ;
// generate high to low transition on the scl line
if (clk_gen_cnt == 'h0)
begin
scl_oe = 1'b1 ;
scl_oe_en = 1'b1 ;
end
// after half of clock low time, disable the sda driver
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
nack_sent = 1'b1 ;
end
// after clock low time, disable the scl driver - generate low to high transition on the scl line
if (clk_gen_cnt == (period_cnt >> 1))
begin
scl_oe = 1'b0 ;
scl_oe_en = 1'b1 ;
end
// after clock period time expires, check what to do next
if (clk_gen_cnt == period_cnt)
begin
clk_gen_cnt_clr = 1'b1 ;
// after the no acknowledge is sent, the only possible next state is stop
// state
if (send_stop)
tx_rx_next_state = tx_rx_stop ;
else
begin
// this should never happen
tx_rx_next_state = tx_rx_idle ;
end
end
end
tx_rx_restart:
begin
clk_gen_cnt_en = 1'b1 ;
// generate high to low transition
if (clk_gen_cnt == 'h0)
begin
scl_oe = 1'b1 ;
scl_oe_en = 1'b1 ;
end
// after half of clock low time, release sda line
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
end
// generate low to high transition
if (clk_gen_cnt == (period_cnt >> 1))
begin
clk_gen_cnt_clr = 1'b1 ;
scl_oe = 1'b0 ;
scl_oe_en = 1'b1 ;
if (send_start)
tx_rx_next_state = tx_rx_start ;
else
tx_rx_next_state = tx_rx_idle ;
end
end
tx_rx_stop:
begin
clk_gen_cnt_en = 1'b1 ;
// generate high to low transition
if (clk_gen_cnt == 'h0)
begin
scl_oe = 1'b1 ;
scl_oe_en = 1'b1 ;
end
// after half of clock low time, drive sda line low
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = 1'b1 ;
sda_oe_en = 1'b1 ;
end
// generate low to high transition
if (clk_gen_cnt == (period_cnt >> 1))
begin
scl_oe = 1'b0 ;
scl_oe_en = 1'b1 ;
end
// after full clock period, release the sda line
if (clk_gen_cnt == period_cnt)
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
stop_sent = 1'b1 ;
tx_rx_next_state = tx_rx_idle ;
end
end
endcase
end
reg [rw_seq_state_width - 1:0] rw_seq_state ;
reg doing_read ,
doing_write ,
doing_seq_read ,
adr_set ;
reg [ 3: 0] bits_transfered ;
always@(posedge clk_i or posedge reset_i)
begin
if (reset_i)
begin
rw_seq_state <= rw_seq_idle ;
adr_set <= 1'b0 ;
doing_read <= 1'b0 ;
doing_write <= 1'b0 ;
doing_seq_read <= 1'b0 ;
dat_o <= 'h0 ;
tx_shift_reg <= 'h0 ;
send_start <= 'h0 ;
send_stop <= 'h0 ;
send_bit <= 'h0 ;
send_nack <= 'h0 ;
rec_ack <= 'h0 ;
no_ack_o <= 'h0 ;
bits_transfered <= 'h0 ;
write_done_o <= 'h0 ;
dat_rdy_o <= 'h0 ;
send_ack <= 'h0 ;
rec_bit <= 'h0 ;
end
else
begin
case (rw_seq_state)
rw_seq_idle:
begin
tx_shift_reg <= {4'b1010, adr_i[10: 8], 1'b0} ;
adr_set <= 1'b0 ;
if ( tx_rx_sm_idle & ~(doing_write | doing_read | doing_seq_read) )
begin
if (do_write_i | do_rnd_read_i | do_seq_read_i)
begin
rw_seq_state <= rw_seq_tx_ctrl ;
send_start <= 1'b1 ;
end
if (do_write_i)
doing_write <= 1'b1 ;
else if (do_rnd_read_i)
doing_read <= 1'b1 ;
else if (do_seq_read_i)
doing_seq_read <= 1'b1 ;
end
else
begin
doing_write <= 1'b0 ;
doing_read <= 1'b0 ;
doing_seq_read <= 1'b0 ;
end
end
rw_seq_tx_ctrl:
begin
if (send_start)
begin
bits_transfered <= 'h0 ;
if (start_sent)
begin
send_start <= 1'b0 ;
send_bit <= 1'b1 ;
end
end
else if (send_bit)
begin
if (bit_sent)
begin
bits_transfered <= bits_transfered + 1'b1 ;
tx_shift_reg <= {tx_shift_reg[6:0], tx_shift_reg[0]} ;
end
if (bits_transfered == 'h8)
begin
send_bit <= 1'b0 ;
rec_ack <= 1'b1 ;
end
end
else if (rec_ack)
begin
bits_transfered <= 'h0 ;
if (ack_rec | nack_rec)
rec_ack <= 1'b0 ;
if (ack_rec)
begin
if (doing_write | ~adr_set)
begin
rw_seq_state <= rw_seq_tx_adr ;
tx_shift_reg <= adr_i[ 7: 0] ;
send_bit <= 1'b1 ;
end
else
begin
rw_seq_state <= rw_seq_rx_byte ;
rec_bit <= 1'b1 ;
end
end
else if (nack_rec)
begin
no_ack_o <= 1'b1 ;
send_stop <= 1'b1 ;
end
end
else if (send_stop)
begin
no_ack_o <= 1'b0 ;
if (stop_sent)
begin
send_stop <= 1'b0 ;
rw_seq_state <= rw_seq_idle ;
end
end
end
rw_seq_tx_adr:
begin
if (send_bit)
begin
if (bit_sent)
begin
bits_transfered <= bits_transfered + 1'b1 ;
tx_shift_reg <= {tx_shift_reg[6:0], tx_shift_reg[0]} ;
end
if (bits_transfered == 'h8)
begin
send_bit <= 1'b0 ;
rec_ack <= 1'b1 ;
end
end
else if (rec_ack)
begin
bits_transfered <= 'h0 ;
if (ack_rec | nack_rec)
rec_ack <= 1'b0 ;
if (ack_rec)
begin
adr_set <= 1'b1 ;
if (doing_write)
begin
send_bit <= 1'b1 ;
rw_seq_state <= rw_seq_tx_byte ;
tx_shift_reg <= dat_i ;
end
else if (doing_read | doing_seq_read)
begin
send_start <= 1'b1 ;
rw_seq_state <= rw_seq_tx_ctrl ;
tx_shift_reg <= 8'b10100001 ;
end
end
else if (nack_rec)
begin
no_ack_o <= 1'b1 ;
send_stop <= 1'b1 ;
end
end
else if (send_stop)
begin
no_ack_o <= 1'b0 ;
if (stop_sent)
begin
send_stop <= 1'b0 ;
rw_seq_state <= rw_seq_idle ;
end
end
end
rw_seq_tx_byte:
begin
if (send_bit)
begin
if (bit_sent)
begin
bits_transfered <= bits_transfered + 1'b1 ;
tx_shift_reg <= {tx_shift_reg[6:0], tx_shift_reg[0]} ;
end
if (bits_transfered == 'h8)
begin
send_bit <= 1'b0 ;
rec_ack <= 1'b1 ;
end
end
else if (rec_ack)
begin
bits_transfered <= 'h0 ;
if (ack_rec | nack_rec)
begin
rec_ack <= 1'b0 ;
send_stop <= 1'b1 ;
end
if (nack_rec)
no_ack_o <= 1'b1 ;
if (ack_rec)
write_done_o <= 1'b1 ;
end
else if (send_stop)
begin
no_ack_o <= 1'b0 ;
write_done_o <= 1'b0 ;
if (stop_sent)
begin
send_stop <= 1'b0 ;
rw_seq_state <= rw_seq_idle ;
end
end
end
rw_seq_rx_byte:
begin
if (rec_bit)
begin
if (bit_rec)
begin
bits_transfered <= bits_transfered + 1'b1 ;
dat_o <= {dat_o[6:0], sda_i_reg} ;
end
if (bits_transfered == 'h8)
begin
rec_bit <= 1'b0 ;
dat_rdy_o <= 1'b1 ;
if (doing_read)
send_nack <= 1'b1 ;
else
send_ack <= 1'b1 ;
end
end
else if (send_nack)
begin
dat_rdy_o <= 1'b0 ;
bits_transfered <= 'h0 ;
if (nack_sent)
begin
send_stop <= 1'b1 ;
send_nack <= 1'b0 ;
end
end
else if (send_ack)
begin
dat_rdy_o <= 1'b0 ;
bits_transfered <= 'h0 ;
if (~do_seq_read_i)
begin
send_ack <= 1'b0 ;
send_nack <= 1'b1 ;
end
else if (ack_sent)
begin
send_ack <= 1'b0 ;
rec_bit <= 1'b1 ;
end
end
else if (send_stop)
begin
if (stop_sent)
begin
send_stop <= 1'b0 ;
rw_seq_state <= rw_seq_idle ;
end
end
end
endcase
end
end
endmodule // pci_spoci_ctrl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -