⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci_spoci_ctrl.v

📁 用verilog编写的pci——rtl级。
💻 V
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////
////                                                              ////
////  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 + -