]> git.zerfleddert.de Git - raggedstone/blobdiff - ethernet/source/pci/pci_master32_sm.v
add shit
[raggedstone] / ethernet / source / pci / pci_master32_sm.v
diff --git a/ethernet/source/pci/pci_master32_sm.v b/ethernet/source/pci/pci_master32_sm.v
new file mode 100644 (file)
index 0000000..29fdf08
--- /dev/null
@@ -0,0 +1,618 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  File name "pci_master32_sm.v"                               ////
+////                                                              ////
+////  This file is part of the "PCI bridge" project               ////
+////  http://www.opencores.org/cores/pci/                         ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Miha Dolenc (mihad@opencores.org)                     ////
+////                                                              ////
+////  All additional information is avaliable in the README       ////
+////  file.                                                       ////
+////                                                              ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2001 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 software; 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_master32_sm.v,v $
+// Revision 1.1  2007-03-20 17:50:56  sithglan
+// add shit
+//
+// Revision 1.5  2003/01/27 16:49:31  mihad
+// Changed module and file names. Updated scripts accordingly. FIFO synchronizations changed.
+//
+// Revision 1.4  2003/01/21 16:06:56  mihad
+// Bug fixes, testcases added.
+//
+// Revision 1.3  2002/02/01 15:25:12  mihad
+// Repaired a few bugs, updated specification, added test bench files and design document
+//
+// Revision 1.2  2001/10/05 08:14:29  mihad
+// Updated all files with inclusion of timescale file for simulation purposes.
+//
+// Revision 1.1.1.1  2001/10/02 15:33:46  mihad
+// New project directory structure
+//
+//
+
+// module includes pci master state machine and surrounding logic
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+`include "pci_constants.v"
+
+module pci_master32_sm
+(
+    // system inputs
+    clk_in,
+    reset_in,
+    // arbitration
+    pci_req_out,
+    pci_gnt_in,
+    // master in/outs
+    pci_frame_in,
+    pci_frame_out,
+    pci_frame_out_in,
+    pci_frame_load_out,
+    pci_frame_en_in,
+    pci_frame_en_out,
+    pci_irdy_in,
+    pci_irdy_out,
+    pci_irdy_en_out,
+
+    // target response inputs
+    pci_trdy_in,
+    pci_trdy_reg_in,
+    pci_stop_in,
+    pci_stop_reg_in,
+    pci_devsel_in,
+    pci_devsel_reg_in,
+
+    // address, data, bus command, byte enable in/outs
+    pci_ad_reg_in,
+    pci_ad_out,
+    pci_ad_en_out,
+    pci_cbe_out,
+    pci_cbe_en_out,
+
+    // other side of state machine
+    address_in,
+    bc_in,
+    data_in,
+    data_out,
+    be_in,
+    req_in,
+    rdy_in,
+    last_in,
+    next_data_in,
+    next_be_in,
+    next_last_in,
+    ad_load_out,
+    ad_load_on_transfer_out,
+    wait_out,
+    wtransfer_out,
+    rtransfer_out,
+    retry_out,
+    rerror_out,
+    first_out,
+    mabort_out,
+    latency_tim_val_in
+) ;
+
+// system inputs
+input   clk_in,
+        reset_in ;
+
+/*==================================================================================================================
+PCI interface signals - bidirectional signals are divided to inputs and outputs in I/O cells instantiation
+module. Enables are separate signals.
+==================================================================================================================*/
+// arbitration
+output  pci_req_out ;
+
+input   pci_gnt_in ;
+
+// master in/outs
+input   pci_frame_in ;
+input   pci_frame_en_in ;
+input   pci_frame_out_in ;
+
+output  pci_frame_out,
+        pci_frame_en_out ;
+
+output  pci_frame_load_out ;
+
+input   pci_irdy_in ;
+output  pci_irdy_out,
+        pci_irdy_en_out;
+
+// target response inputs
+input   pci_trdy_in,
+        pci_trdy_reg_in,
+        pci_stop_in,
+        pci_stop_reg_in,
+        pci_devsel_in,
+        pci_devsel_reg_in ;
+
+// address, data, bus command, byte enable in/outs
+input   [31:0]  pci_ad_reg_in ;
+output  [31:0]  pci_ad_out ;
+
+reg     [31:0]  pci_ad_out ;
+
+output          pci_ad_en_out ;
+
+output  [3:0]   pci_cbe_out ;
+
+reg     [3:0]   pci_cbe_out ;
+
+output          pci_cbe_en_out ;
+
+input   [31:0]  address_in ; // current request address input
+
+input   [3:0]   bc_in ;      // current request bus command input
+
+input   [31:0]  data_in ;    // current dataphase data input
+
+output  [31:0]  data_out ;    // for read operations - current request data output
+
+reg     [31:0]  data_out ;
+
+input   [3:0]   be_in ;      // current dataphase byte enable inputs
+
+input           req_in ;     // initiator cycle is requested
+input           rdy_in ;     // requestor indicates that data is ready to be sent for write transaction and ready to
+                            // be received on read transaction
+input           last_in ;    // last dataphase in current transaction indicator
+
+// status outputs
+output wait_out,            // wait indicates to the backend that dataphases are not in progress on PCI bus
+       wtransfer_out,       // on any rising clock edge that this status is 1, data is transferred - heavy constraints here
+       rtransfer_out,       // registered transfer indicator - when 1 indicates that data was transfered on previous clock cycle
+       retry_out,           // retry status output - when target signals a retry
+       rerror_out,          // registered error output - when 1 indicates that error was signalled by a target on previous clock cycle
+       first_out ,          // indicates whether or not any data was transfered in current transaction
+       mabort_out;          // master abort indicator
+
+reg wait_out ;
+
+// latency timer value input - state machine starts latency timer whenever it starts a transaction and last is not
+// asserted ( meaning burst transfer ).
+input [7:0] latency_tim_val_in ;
+
+// next data, byte enable and last inputs
+input [31:0] next_data_in ;
+input [3:0]  next_be_in ;
+input        next_last_in ;
+
+// clock enable for data output flip-flops - whenever data is transfered, sm loads next data to those flip flops
+output       ad_load_out,
+             ad_load_on_transfer_out ;
+
+// parameters - states - one hot
+// idle state
+parameter S_IDLE            = 4'h1 ;
+
+// address state
+parameter S_ADDRESS         = 4'h2 ;
+
+// transfer state - dataphases
+parameter S_TRANSFER        = 4'h4 ;
+
+// turn arround state
+parameter S_TA_END          = 4'h8 ;
+
+// change state - clock enable for sm state register
+wire change_state ;
+// next state for state machine
+reg [3:0] next_state ;
+// SM state register
+reg [3:0] cur_state ;
+
+// variables for indicating which state state machine is in
+// this variables are used to reduce logic levels in case of heavily constrained PCI signals
+reg sm_idle            ;
+reg sm_address         ;
+reg sm_data_phases     ;
+reg sm_turn_arround    ;
+
+// state machine register control logic with clock enable
+always@(posedge reset_in or posedge clk_in)
+begin
+    if (reset_in)
+        cur_state <= #`FF_DELAY S_IDLE ;
+    else
+    if ( change_state )
+        cur_state <= #`FF_DELAY next_state ;
+end
+
+// parameters - data selector - ad and bc lines switch between address/data and bus command/byte enable respectively
+parameter SEL_ADDR_BC      = 2'b01 ;
+parameter SEL_DATA_BE      = 2'b00 ;
+parameter SEL_NEXT_DATA_BE = 2'b11 ;
+
+reg [1:0] wdata_selector ;
+
+wire u_dont_have_pci_bus = pci_gnt_in || ~pci_frame_in || ~pci_irdy_in ;    // pci master can't start a transaction when GNT is deasserted ( 1 ) or
+                                                                            // bus is not in idle state ( FRAME and IRDY both 1 )
+wire u_have_pci_bus      = ~pci_gnt_in && pci_frame_in && pci_irdy_in ;
+
+// decode count enable - counter that counts cycles passed since address phase
+wire        sm_decode_count_enable = sm_data_phases ;                                                               // counter is enabled when master wants to transfer
+wire        decode_count_enable    = sm_decode_count_enable && pci_trdy_in && pci_stop_in && pci_devsel_in ;        // and target is not responding
+wire        decode_count_load      = ~decode_count_enable ;
+reg [2:0]   decode_count ;
+
+wire decode_to = ~( decode_count[2] || decode_count[1]) ;
+
+always@(posedge reset_in or posedge clk_in)
+begin
+    if ( reset_in )
+        // initial value of counter is 4
+        decode_count <= #`FF_DELAY 3'h4 ;
+    else
+    if ( decode_count_load )
+        decode_count <= #`FF_DELAY 3'h4 ;
+    else
+    if ( decode_count_enable )
+        decode_count <= #`FF_DELAY decode_count - 1'b1 ;
+end
+
+// Bus commands LSbit indicates whether operation is a read or a write
+wire do_write = bc_in[0] ;
+
+// latency timer
+reg [7:0]   latency_timer ;
+
+wire latency_time_out     = ~(
+                               (latency_timer[7] || latency_timer[6] || latency_timer[5] || latency_timer[4]) ||
+                               (latency_timer[3] || latency_timer[2] || latency_timer[1] )
+                             ) ;
+
+wire latency_timer_enable = (sm_address || sm_data_phases) && ~latency_time_out ;
+wire latency_timer_load   = ~sm_address && ~sm_data_phases ;
+
+always@(posedge clk_in or posedge reset_in)
+begin
+    if (reset_in)
+        latency_timer <= #`FF_DELAY 8'h00 ;
+    else
+    if ( latency_timer_load )
+        latency_timer <= #`FF_DELAY latency_tim_val_in ;
+    else
+    if ( latency_timer_enable)         // latency timer counts down until it expires - then it stops
+        latency_timer <= #`FF_DELAY latency_timer - 1'b1 ;
+end
+
+// master abort indicators - when decode time out occurres and still no target response is received
+wire do_master_abort = decode_to && pci_trdy_in && pci_stop_in && pci_devsel_in ;
+reg mabort1 ;
+always@(posedge reset_in or posedge clk_in)
+begin
+    if (reset_in)
+        mabort1 <= #`FF_DELAY 1'b0 ;
+    else
+        mabort1 <= #`FF_DELAY do_master_abort ;
+end
+
+reg mabort2 ;
+always@(posedge reset_in or posedge clk_in)
+begin
+    if ( reset_in )
+        mabort2 <= #`FF_DELAY 1'b0 ;
+    else
+        mabort2 <= #`FF_DELAY mabort1 ;
+end
+
+// master abort is only asserted for one clock cycle
+assign mabort_out = mabort1 && ~mabort2 ;
+
+// register indicating when master should do timeout termination (latency timer expires)
+reg timeout ;
+always@(posedge reset_in or posedge clk_in)
+begin
+    if (reset_in)
+        timeout <= #`FF_DELAY 1'b0 ;
+    else
+        timeout <= #`FF_DELAY (latency_time_out && ~pci_frame_out_in && pci_gnt_in || timeout ) && ~wait_out ;
+end
+
+wire timeout_termination = sm_turn_arround && timeout && pci_stop_reg_in ;
+
+// frame control logic
+// frame is forced to 0 (active) when state machine is in idle state, since only possible next state is address state which always drives frame active
+wire force_frame = ~sm_idle ;
+// slow signal for frame calculated from various registers in the core
+wire slow_frame  = last_in || (latency_time_out && pci_gnt_in) || (next_last_in && sm_data_phases) || mabort1 ;
+// critical timing frame logic in separate module - some combinations of target signals force frame to inactive state immediately after sampled asserted
+// (STOP)
+pci_frame_crit frame_iob_feed
+(
+    .pci_frame_out      (pci_frame_out),
+    .force_frame_in     (force_frame),
+    .slow_frame_in      (slow_frame),
+    .pci_stop_in        (pci_stop_in)
+) ;
+
+// frame IOB flip flop's clock enable signal
+// slow clock enable - calculated from internal - non critical paths
+wire frame_load_slow = sm_idle || sm_address || mabort1 ;
+
+// critical clock enable for frame IOB in separate module - target response signals actually allow frame value change - critical timing
+pci_frame_load_crit frame_iob_ce
+(
+    .pci_frame_load_out (pci_frame_load_out),
+    .sm_data_phases_in  (sm_data_phases),
+    .frame_load_slow_in (frame_load_slow),
+    .pci_trdy_in        (pci_trdy_in),
+    .pci_stop_in        (pci_stop_in)
+) ;
+
+// IRDY driving
+// non critical path for IRDY calculation
+wire irdy_slow = pci_frame_out_in && mabort1 || mabort2 ;
+
+// critical path in separate module
+pci_irdy_out_crit irdy_iob_feed
+(
+    .pci_irdy_out       (pci_irdy_out),
+    .irdy_slow_in       (irdy_slow),
+    .pci_frame_out_in   (pci_frame_out_in),
+    .pci_trdy_in        (pci_trdy_in),
+    .pci_stop_in        (pci_stop_in)
+) ;
+
+// transfer FF indicator - when first transfer occurs it is set to 1 so backend can distinguish between disconnects and retries.
+wire sm_transfer = sm_data_phases ;
+reg transfer ;
+
+wire transfer_input = sm_transfer && (~(pci_trdy_in || pci_devsel_in) || transfer) ;
+
+always@(posedge clk_in or posedge reset_in)
+begin
+    if (reset_in)
+        transfer <= #`FF_DELAY 1'b0 ;
+    else
+        transfer <= #`FF_DELAY transfer_input ;
+end
+
+assign first_out = ~transfer ;
+
+// fast transfer status output - it's only negated target ready, since wait indicator qualifies valid transfer
+assign wtransfer_out = ~pci_trdy_in ;
+
+// registered transfer status output - calculated from registered target response inputs
+assign rtransfer_out = ~(pci_trdy_reg_in || pci_devsel_reg_in) ;
+
+// registered error status - calculated from registered target response inputs
+assign rerror_out    = (~pci_stop_reg_in && pci_devsel_reg_in) ;
+
+// retry is signalled to backend depending on registered target response or when latency timer expires
+assign retry_out = timeout_termination || (~pci_stop_reg_in && ~pci_devsel_reg_in) ;
+
+// AD output flip flops' clock enable
+// new data is loaded to AD outputs whenever state machine is idle, bus was granted and bus is in idle state or
+// when address phase is about to be finished
+wire ad_load_slow = sm_address ;
+wire ad_load_on_grant = sm_idle && pci_frame_in && pci_irdy_in ;
+
+pci_mas_ad_load_crit mas_ad_load_feed
+(
+    .ad_load_out         (ad_load_out),
+    .ad_load_in          (ad_load_slow),
+    .ad_load_on_grant_in (ad_load_on_grant),
+    .pci_gnt_in          (pci_gnt_in)
+);
+
+// next data loading is allowed when state machine is in transfer state and operation is a write
+assign ad_load_on_transfer_out = sm_data_phases && do_write ;
+
+// request for a bus is issued anytime when backend is requesting a transaction and state machine is in idle state
+assign pci_req_out = ~(req_in && sm_idle) ;
+
+// change state signal is actually clock enable for state register
+// Non critical path for state change enable:
+// state is always changed when:
+// - address phase is finishing
+// - state machine is in turn arround state
+// - state machine is in transfer state and master abort termination is in progress
+
+wire ch_state_slow = sm_address || sm_turn_arround || sm_data_phases && ( pci_frame_out_in && mabort1 || mabort2 ) ;
+
+// a bit more critical change state enable is calculated with GNT signal
+wire ch_state_med  = ch_state_slow || sm_idle && u_have_pci_bus && req_in && rdy_in ;
+
+// most critical change state enable - calculated from target response signals
+pci_mas_ch_state_crit state_machine_ce
+(
+    .change_state_out   (change_state),
+    .ch_state_med_in    (ch_state_med),
+    .sm_data_phases_in  (sm_data_phases),
+    .pci_trdy_in        (pci_trdy_in),
+    .pci_stop_in        (pci_stop_in)
+) ;
+
+// ad enable driving
+// also divided in several categories - from less critical to most critical in separate module
+//wire ad_en_slowest  = do_write && (sm_address || sm_data_phases && ~pci_frame_out_in) ;
+//wire ad_en_on_grant = sm_idle && pci_frame_in && pci_irdy_in || sm_turn_arround ;
+//wire ad_en_slow     = ad_en_on_grant && ~pci_gnt_in || ad_en_slowest ;
+//wire ad_en_keep     = sm_data_phases && do_write && (pci_frame_out_in && ~mabort1 && ~mabort2) ;
+
+wire ad_en_slow     = do_write && ( sm_address || ( sm_data_phases && !( ( pci_frame_out_in && mabort1 ) || mabort2 ) ) ) ;
+wire ad_en_on_grant = ( sm_idle && pci_frame_in && pci_irdy_in ) || sm_turn_arround ;
+
+// critical timing ad enable - calculated from grant input
+pci_mas_ad_en_crit ad_iob_oe_feed
+(
+    .pci_ad_en_out      (pci_ad_en_out),
+    .ad_en_slow_in      (ad_en_slow),
+    .ad_en_on_grant_in  (ad_en_on_grant),
+    .pci_gnt_in         (pci_gnt_in)
+) ;
+
+// cbe enable driving
+wire cbe_en_on_grant = sm_idle && pci_frame_in && pci_irdy_in || sm_turn_arround ;
+wire cbe_en_slow     = cbe_en_on_grant && ~pci_gnt_in || sm_address || sm_data_phases && ~pci_frame_out_in ;
+wire cbe_en_keep     = sm_data_phases && pci_frame_out_in && ~mabort1 && ~mabort2 ;
+
+// most critical cbe enable in separate module - calculated with most critical target inputs
+pci_cbe_en_crit cbe_iob_feed
+(
+    .pci_cbe_en_out     (pci_cbe_en_out),
+    .cbe_en_slow_in     (cbe_en_slow),
+    .cbe_en_keep_in     (cbe_en_keep),
+    .pci_stop_in        (pci_stop_in),
+    .pci_trdy_in        (pci_trdy_in)
+
+) ;
+
+// IRDY enable is equal to FRAME enable delayed for one clock
+assign pci_irdy_en_out   = pci_frame_en_in ;
+
+// frame enable driving - sometimes it's calculated from non critical paths
+wire frame_en_slow = (sm_idle && u_have_pci_bus && req_in && rdy_in) || sm_address || (sm_data_phases && ~pci_frame_out_in) ;
+wire frame_en_keep = sm_data_phases && pci_frame_out_in && ~mabort1 && ~mabort2 ;
+
+// most critical frame enable - calculated from heavily constrained target inputs in separate module
+pci_frame_en_crit frame_iob_en_feed
+(
+    .pci_frame_en_out   (pci_frame_en_out),
+    .frame_en_slow_in   (frame_en_slow),
+    .frame_en_keep_in   (frame_en_keep),
+    .pci_stop_in        (pci_stop_in),
+    .pci_trdy_in        (pci_trdy_in)
+) ;
+
+// state machine next state definitions
+always@(
+    cur_state or
+    do_write or
+    pci_frame_out_in
+)
+begin
+    // default values for state machine outputs
+    wait_out                = 1'b1 ;
+    wdata_selector          = SEL_ADDR_BC ;
+    sm_idle                 = 1'b0 ;
+    sm_address              = 1'b0 ;
+    sm_data_phases          = 1'b0 ;
+    sm_turn_arround         = 1'b0 ;
+
+    case ( cur_state )
+
+        S_IDLE: begin
+                    // indicate the state
+                    sm_idle      = 1'b1 ;
+                    // assign next state - only possible is address - if state machine is supposed to stay in idle state
+                    // outside signals disable the clock
+                    next_state     = S_ADDRESS ;
+                    wdata_selector = SEL_DATA_BE ;
+                end
+
+        S_ADDRESS:  begin
+                        // indicate the state
+                        sm_address  = 1'b1 ;
+                        // select appropriate data/be for outputs
+                        wdata_selector = SEL_NEXT_DATA_BE ;
+                        // only possible next state is transfer state
+                        next_state = S_TRANSFER ;
+                    end
+
+        S_TRANSFER: begin
+                        // during transfers wait indicator is inactive - all status signals are now valid
+                        wait_out               = 1'b0 ;
+                        // indicate the state
+                        sm_data_phases         = 1'b1 ;
+                        // select appropriate data/be for outputs
+                        wdata_selector = SEL_NEXT_DATA_BE ;
+                        if ( pci_frame_out_in )
+                        begin
+                            // when frame is inactive next state will be turn arround
+                            next_state = S_TA_END ;
+                        end
+                        else
+                            // while frame is active state cannot be anything else then transfer
+                            next_state = S_TRANSFER ;
+                    end
+
+        S_TA_END:   begin
+                        // wait is still inactive because of registered statuses
+                        wait_out = 1'b0 ;
+                        // indicate the state
+                        sm_turn_arround = 1'b1 ;
+                        // next state is always idle
+                        next_state = S_IDLE ;
+                    end
+        default:    next_state = S_IDLE ;
+    endcase
+end
+
+// ad and cbe lines multiplexer for write data
+reg [1:0] rdata_selector ;
+always@(posedge clk_in or posedge reset_in)
+begin
+    if ( reset_in )
+        rdata_selector <= #`FF_DELAY SEL_ADDR_BC ;
+    else
+    if ( change_state )
+        rdata_selector <= #`FF_DELAY wdata_selector ;
+end
+
+always@(rdata_selector or address_in or bc_in or data_in or be_in or next_data_in or next_be_in)
+begin
+    case ( rdata_selector )
+        SEL_ADDR_BC:    begin
+                            pci_ad_out  = address_in ;
+                            pci_cbe_out = bc_in ;
+                        end
+
+        SEL_DATA_BE:    begin
+                            pci_ad_out  = data_in ;
+                            pci_cbe_out = be_in ;
+                        end
+        SEL_NEXT_DATA_BE,
+        2'b10:              begin
+                                pci_ad_out  = next_data_in ;
+                                pci_cbe_out = next_be_in ;
+                            end
+    endcase
+end
+
+// data output mux for reads
+always@(mabort_out or pci_ad_reg_in)
+begin
+    if ( mabort_out )
+        data_out = 32'hFFFF_FFFF ;
+    else
+        data_out = pci_ad_reg_in ;
+end
+endmodule
Impressum, Datenschutz