📄 pci_spoci_ctrl.v
字号:
//////////////////////////////////////////////////////////////////////
//// ////
//// File name: pci_spoci_ctrl ////
//// ////
//// This file is part of the "PCI bridge" project ////
//// http://www.opencores.org/cores/pci/ ////
//// ////
//// Author(s): ////
//// - Miha Dolenc (mihad@opencores.org) ////
//// ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2004 Miha Dolenc, mihad@opencores.org ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
//
// CVS Revision History
//
// $Log: pci_spoci_ctrl.v,v $
// Revision 1.1 2004/01/24 11:54:18 mihad
// Update! SPOCI Implemented!
//
//
`include "pci_constants.v"
// synopsys translate_off
`include "timescale.v"
// synopsys translate_on
module pci_spoci_ctrl
(
reset_i ,
clk_i ,
do_rnd_read_i ,
do_seq_read_i ,
do_write_i ,
write_done_o ,
dat_rdy_o ,
no_ack_o ,
adr_i ,
dat_i ,
dat_o ,
pci_spoci_sda_i ,
pci_spoci_sda_oe_o ,
pci_spoci_scl_oe_o
);
parameter tx_rx_state_width = 9 ;
parameter tx_rx_idle = 'h1 ;
parameter tx_rx_start = 'h2 ;
parameter tx_rx_restart = 'h4 ;
parameter tx_rx_send_bits = 'h8 ;
parameter tx_rx_rec_bits = 'h10 ;
parameter tx_rx_send_ack = 'h20 ;
parameter tx_rx_rec_ack = 'h40 ;
parameter tx_rx_send_nack = 'h80 ;
parameter tx_rx_stop = 'h100 ;
parameter rw_seq_state_width = 5 ;
parameter rw_seq_idle = 'h1 ;
parameter rw_seq_tx_ctrl = 'h2 ;
parameter rw_seq_tx_adr = 'h4 ;
parameter rw_seq_tx_byte = 'h8 ;
parameter rw_seq_rx_byte = 'h10 ;
`ifdef PCI33
parameter cnt_width = 9 ;
parameter period_cnt = 334 ;
`endif
`ifdef PCI66
parameter cnt_width = 10 ;
parameter period_cnt = 667 ;
`endif
input reset_i ,
clk_i ;
input do_rnd_read_i ,
do_seq_read_i ,
do_write_i ;
output write_done_o ,
dat_rdy_o ,
no_ack_o ;
input [10: 0] adr_i ;
input [ 7: 0] dat_i ;
output [ 7: 0] dat_o ;
input pci_spoci_sda_i ;
output pci_spoci_sda_oe_o ,
pci_spoci_scl_oe_o ;
reg write_done_o ,
dat_rdy_o ,
no_ack_o ;
reg [ 7: 0] dat_o ;
reg pci_spoci_sda_oe_o ,
pci_spoci_scl_oe_o ;
reg clk_gen_cnt_en ;
reg clk_gen_cnt_clr ;
reg [cnt_width - 1:0] clk_gen_cnt ;
reg [tx_rx_state_width - 1:0] tx_rx_state ;
reg [tx_rx_state_width - 1:0] tx_rx_next_state ;
reg tx_rx_sm_idle ;
reg scl_oe ;
reg scl_oe_en ;
reg sda_oe ;
reg sda_oe_en ;
reg sda_i_reg_en ;
reg sda_i_reg ;
always@(posedge clk_i or posedge reset_i)
begin
if (reset_i)
begin
clk_gen_cnt <= 'h0 ;
tx_rx_state <= tx_rx_idle ;
`ifdef ACTIVE_LOW_OE
pci_spoci_sda_oe_o <= 1'b1 ;
pci_spoci_scl_oe_o <= 1'b1 ;
`endif
`ifdef ACTIVE_HIGH_OE
pci_spoci_sda_oe_o <= 1'b0 ;
pci_spoci_scl_oe_o <= 1'b0 ;
`endif
sda_i_reg <= 1'b1 ;
end
else
begin
tx_rx_state <= tx_rx_next_state ;
if (clk_gen_cnt_clr)
clk_gen_cnt <= 'h0 ;
else if (clk_gen_cnt_en)
clk_gen_cnt <= clk_gen_cnt + 1'b1 ;
if (sda_oe_en)
begin
`ifdef ACTIVE_LOW_OE
pci_spoci_sda_oe_o <= ~sda_oe ;
`endif
`ifdef ACTIVE_HIGH_OE
pci_spoci_sda_oe_o <= sda_oe ;
`endif
end
if (scl_oe_en)
begin
`ifdef ACTIVE_LOW_OE
pci_spoci_scl_oe_o <= ~scl_oe ;
`endif
`ifdef ACTIVE_HIGH_OE
pci_spoci_scl_oe_o <= scl_oe ;
`endif
end
if (sda_i_reg_en)
sda_i_reg <= pci_spoci_sda_i ;
end
end
reg [ 7: 0] tx_shift_reg ;
reg send_start ;
reg start_sent ;
reg send_bit ;
reg bit_sent ;
reg rec_bit ;
reg bit_rec ;
reg rec_ack ;
reg ack_rec ;
reg nack_rec ;
reg send_ack ;
reg ack_sent ;
reg send_nack ;
reg nack_sent ;
reg send_stop ;
reg stop_sent ;
always@
(
tx_rx_state or
clk_gen_cnt or
send_start or
send_bit or
tx_shift_reg or
send_stop or
rec_ack or
sda_i_reg or
rec_bit or
send_ack or
send_nack
)
begin
clk_gen_cnt_clr = 1'b0 ;
clk_gen_cnt_en = 1'b0 ;
tx_rx_next_state = tx_rx_state ;
tx_rx_sm_idle = 1'b0 ;
scl_oe = 1'b0 ;
sda_oe = 1'b0 ;
scl_oe_en = 1'b0 ;
sda_oe_en = 1'b0 ;
start_sent = 1'b0 ;
bit_sent = 1'b0 ;
ack_rec = 1'b0 ;
nack_rec = 1'b0 ;
sda_i_reg_en = 1'b0 ;
stop_sent = 1'b0 ;
bit_rec = 1'b0 ;
ack_sent = 1'b0 ;
nack_sent = 1'b0 ;
case (tx_rx_state)
tx_rx_idle:
begin
tx_rx_sm_idle = 1'b1 ;
// from idle state, the only transition can be to the send start bit
if (send_start)
begin
tx_rx_next_state = tx_rx_start ;
clk_gen_cnt_clr = 1'b1 ;
end
end
tx_rx_start:
begin
clk_gen_cnt_en = 1'b1 ;
sda_oe = 1'b1 ;
// start bit is sent by transmiting 0 on the sda line
if (clk_gen_cnt == (period_cnt >> 1))
begin
start_sent = 1'b1 ;
sda_oe_en = 1'b1 ;
end
// after half clock period of driving the sda low, the only possible
// transition is to send state.
// if send bit is not active, stop the procedure - undrive sda
if (clk_gen_cnt == period_cnt)
begin
clk_gen_cnt_clr = 1'b1 ;
if (send_bit)
begin
tx_rx_next_state = tx_rx_send_bits ;
end
else
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
tx_rx_next_state = tx_rx_idle ;
end
end
end
tx_rx_send_bits:
begin
clk_gen_cnt_en = 1'b1 ;
// generate high to low transition on the scl line immediately
if (clk_gen_cnt == 'h0)
begin
scl_oe = 1'b1 ;
scl_oe_en = 1'b1 ;
end
// after half of clock low time, load new value for sda oe, depending on the
// msb bit in the shift register
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = ~tx_shift_reg[7] ;
sda_oe_en = 1'b1 ;
bit_sent = 1'b1 ;
end
// after clock low time, 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 high time, check what to do next
if (clk_gen_cnt == (period_cnt))
begin
clk_gen_cnt_clr = 1'b1 ;
if (~send_bit)
begin
// after transmiting all the bits, the only possible transition is to the state
// that checks the eprom acknowledge
if (rec_ack)
tx_rx_next_state = tx_rx_rec_ack ;
else
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
tx_rx_next_state = tx_rx_idle ;
end
end
end
end
tx_rx_rec_bits:
begin
clk_gen_cnt_en = 1'b1 ;
sda_i_reg_en = 1'b1 ;
// generate high to low transition on the scl line immediately
if (clk_gen_cnt == 'h0)
begin
scl_oe = 1'b1 ;
scl_oe_en = 1'b1 ;
end
// after half of clock low time, disable sda driver
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
end
// after clock low time, 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 half of clock high time, report received bit
if (clk_gen_cnt == ((period_cnt >> 1) + (period_cnt >> 2)) )
begin
bit_rec = 1'b1 ;
end
// after clock period is finished, check the next operation
if (clk_gen_cnt == (period_cnt))
begin
clk_gen_cnt_clr = 1'b1 ;
if (~rec_bit)
begin
// when all bits are received, only nack or ack next states are possible
if (send_ack)
tx_rx_next_state = tx_rx_send_ack ;
else if (send_nack)
tx_rx_next_state = tx_rx_send_nack ;
else
begin
tx_rx_next_state = tx_rx_idle ;
end
end
end
end
tx_rx_send_ack:
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, enable the sda driver
if (clk_gen_cnt == (period_cnt >> 2))
begin
sda_oe = 1'b1 ;
sda_oe_en = 1'b1 ;
ack_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 byte is acknowledged, the only possible next state is receive bits
// state
if (rec_bit)
tx_rx_next_state = tx_rx_rec_bits ;
else
begin
// this should never happen
sda_oe = 1'b0 ;
sda_oe_en = 1'b1 ;
tx_rx_next_state = tx_rx_idle ;
end
end
end
tx_rx_rec_ack:
begin
clk_gen_cnt_en = 1'b1 ;
sda_i_reg_en = 1'b1 ;
// generate high to low transition on the scl line
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -