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

📄 pci_spoci_ctrl.v

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