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

📄 pci_master32_sm.v

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -