X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/raggedstone/blobdiff_plain/528d015aa19100f9f97b3469ab7d2aafa43b425e..40a1f26c3a09dbd1f71f4fd7f3aca74f387a09db:/ethernet/source/pci/pci_wb_master.v diff --git a/ethernet/source/pci/pci_wb_master.v b/ethernet/source/pci/pci_wb_master.v new file mode 100644 index 0000000..aa7cd5e --- /dev/null +++ b/ethernet/source/pci/pci_wb_master.v @@ -0,0 +1,1176 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// File name: wb_master.v //// +//// //// +//// This file is part of the "PCI bridge" project //// +//// http://www.opencores.org/cores/pci/ //// +//// //// +//// Author(s): //// +//// - Tadej Markovic, tadej@opencores.org //// +//// //// +//// All additional information is avaliable in the README.txt //// +//// file. //// +//// //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2000 Tadej Markovic, tadej@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_wb_master.v,v $ +// Revision 1.1 2007-03-20 17:50:56 sithglan +// add shit +// +// Revision 1.6 2004/01/24 11:54:18 mihad +// Update! SPOCI Implemented! +// +// Revision 1.5 2003/10/24 09:35:40 tadejm +// Added missing signals to 2 sensitivity lists. Everything works the same as before. +// +// Revision 1.4 2003/08/21 20:56:40 tadejm +// WB Master is now WISHBONE B3 compatible. +// +// Revision 1.3 2003/03/14 15:31:57 mihad +// Entered the option to disable no response counter in wb master. +// +// Revision 1.2 2003/01/30 22:01:09 mihad +// Updated synchronization in top level fifo modules. +// +// Revision 1.1 2003/01/27 16:49:31 mihad +// Changed module and file names. Updated scripts accordingly. FIFO synchronizations changed. +// +// Revision 1.7 2002/12/05 12:19:23 mihad +// *** empty log message *** +// +// Revision 1.6 2002/10/11 14:15:29 mihad +// Cleaned up non-blocking assignments in combinatinal logic statements +// +// Revision 1.5 2002/03/05 11:53:47 mihad +// Added some testcases, removed un-needed fifo signals +// +// Revision 1.4 2002/02/19 16:32:37 mihad +// Modified testbench and fixed some bugs +// +// Revision 1.3 2002/02/01 15:25:13 mihad +// Repaired a few bugs, updated specification, added test bench files and design document +// +// Revision 1.2 2001/10/05 08:14:30 mihad +// Updated all files with inclusion of timescale file for simulation purposes. +// +// Revision 1.1.1.1 2001/10/02 15:33:47 mihad +// New project directory structure +// +// + +`define WB_FSM_BITS 3 // number of bits needed for FSM states + + +`include "bus_commands.v" +`include "pci_constants.v" +//synopsys translate_off +`include "timescale.v" +//synopsys translate_on + +module pci_wb_master + ( wb_clock_in, // CLK_I + reset_in, // RST_I + + pci_tar_read_request, + pci_tar_address, + pci_tar_cmd, + pci_tar_be, + pci_tar_burst_ok, + pci_cache_line_size, + cache_lsize_not_zero, + wb_read_done_out, + w_attempt, + + pcir_fifo_wenable_out, + pcir_fifo_data_out, + pcir_fifo_be_out, + pcir_fifo_control_out, + //pcir_fifo_renable_out, for PCI Target !!! + //pcir_fifo_data_in, for PCI Target !!! + //pcir_fifo_be_in, for PCI Target !!! + //pcir_fifo_control_in, for PCI Target !!! + //pcir_fifo_flush_out, for PCI Target !!! + //pcir_fifo_almost_empty_in, for PCI Target !!! + //pcir_fifo_empty_in, NOT used + //pcir_fifo_transaction_ready_in, NOT used + //pciw_fifo_wenable_out, for PCI Target !!! + //pciw_fifo_addr_data_out, for PCI Target !!! + //pciw_fifo_cbe_out, for PCI Target !!! + //pciw_fifo_control_out, for PCI Target !!! + pciw_fifo_renable_out, + pciw_fifo_addr_data_in, + pciw_fifo_cbe_in, + pciw_fifo_control_in, + //pciw_fifo_flush_out, NOT used + //pciw_fifo_almost_full_in, for PCI Target !!! + //pciw_fifo_full_in, for PCI Target !!! + pciw_fifo_almost_empty_in, + pciw_fifo_empty_in, + pciw_fifo_transaction_ready_in, + + pci_error_sig_out, + pci_error_bc, + write_rty_cnt_exp_out, + error_source_out, + read_rty_cnt_exp_out, + + wb_cyc_o, + wb_stb_o, + wb_we_o, + wb_cti_o, + wb_bte_o, + wb_sel_o, + wb_adr_o, + wb_dat_i, + wb_dat_o, + wb_ack_i, + wb_rty_i, + wb_err_i +// CYC_O, +// STB_O, +// WE_O, +// SEL_O, +// ADR_O, +// MDATA_I, +// MDATA_O, +// ACK_I, +// RTY_I, +// ERR_I, + ); + +/*---------------------------------------------------------------------------------------------------------------------- +Various parameters needed for state machine and other stuff +----------------------------------------------------------------------------------------------------------------------*/ +parameter S_IDLE = `WB_FSM_BITS'h0 ; +parameter S_WRITE = `WB_FSM_BITS'h1 ; +parameter S_WRITE_ERR_RTY = `WB_FSM_BITS'h2 ; +parameter S_READ = `WB_FSM_BITS'h3 ; +parameter S_READ_RTY = `WB_FSM_BITS'h4 ; +parameter S_TURN_ARROUND = `WB_FSM_BITS'h5 ; + +/*---------------------------------------------------------------------------------------------------------------------- +System signals inputs +wb_clock_in - WISHBONE bus clock input +reset_in - system reset input controlled by bridge's reset logic +----------------------------------------------------------------------------------------------------------------------*/ +input wb_clock_in ; +input reset_in ; + +/*---------------------------------------------------------------------------------------------------------------------- +Control signals from PCI Target for READS to PCIR_FIFO +---------------------------------------------------------------------------------------------------------------------*/ +input pci_tar_read_request ; // read request from PCI Target +input [31:0] pci_tar_address ; // address for requested read from PCI Target +input [3:0] pci_tar_cmd ; // command for requested read from PCI Target +input [3:0] pci_tar_be ; // byte enables for requested read from PCI Target +input pci_tar_burst_ok ; +input [7:0] pci_cache_line_size ; // CACHE line size register value for burst length +input cache_lsize_not_zero ; +output wb_read_done_out ; // read done and PCIR_FIFO has data ready +output w_attempt ; + +reg wb_read_done_out ; +reg wb_read_done ; + +/*---------------------------------------------------------------------------------------------------------------------- +PCIR_FIFO control signals used for sinking data into PCIR_FIFO and status monitoring +---------------------------------------------------------------------------------------------------------------------*/ +output pcir_fifo_wenable_out ; // PCIR_FIFO write enable output +output [31:0] pcir_fifo_data_out ; // data output to PCIR_FIFO +output [3:0] pcir_fifo_be_out ; // byte enable output to PCIR_FIFO +output [3:0] pcir_fifo_control_out ; // control bus output to PCIR_FIFO + +reg [31:0] pcir_fifo_data_out ; +reg pcir_fifo_wenable_out ; +reg pcir_fifo_wenable ; +reg [3:0] pcir_fifo_control_out ; +reg [3:0] pcir_fifo_control ; + +/*---------------------------------------------------------------------------------------------------------------------- +PCIW_FIFO control signals used for fetching data from PCIW_FIFO and status monitoring +---------------------------------------------------------------------------------------------------------------------*/ +output pciw_fifo_renable_out ; // read enable for PCIW_FIFO output +input [31:0] pciw_fifo_addr_data_in ; // address and data input from PCIW_FIFO +input [3:0] pciw_fifo_cbe_in ; // command and byte_enables from PCIW_FIFO +input [3:0] pciw_fifo_control_in ; // control bus input from PCIW_FIFO +input pciw_fifo_almost_empty_in ; // almost empty status indicator from PCIW_FIFO +input pciw_fifo_empty_in ; // empty status indicator from PCIW_FIFO +input pciw_fifo_transaction_ready_in ; // write transaction is ready in PCIW_FIFO + +reg pciw_fifo_renable_out ; +reg pciw_fifo_renable ; + +/*---------------------------------------------------------------------------------------------------------------------- +Control INPUT / OUTPUT signals for configuration space reporting registers !!! +---------------------------------------------------------------------------------------------------------------------*/ +output pci_error_sig_out ; // When error occures (on WB bus, retry counter, etc.) +output [3:0] pci_error_bc ; // bus command at which error occured ! +output write_rty_cnt_exp_out ; // Signaling that RETRY counter has expired during write transaction! +output read_rty_cnt_exp_out ; // Signaling that RETRY counter has expired during read transaction! + // if error_source is '0' other side didn't respond + // if error_source is '1' other side RETRIED for max retry counter value +output error_source_out ; // Signaling error source - '0' other WB side signaled error OR didn't respond + // if '1' wridge counted max value in retry counter because of RTY responds +reg pci_error_sig_out ; +reg write_rty_cnt_exp_out ; +reg read_rty_cnt_exp_out ; +reg error_source_out ; + +/*---------------------------------------------------------------------------------------------------------------------- +WISHBONE bus interface signals - can be connected directly to WISHBONE bus +---------------------------------------------------------------------------------------------------------------------*/ +output wb_cyc_o; // cycle indicator output +output wb_stb_o; // strobe output - data is valid when strobe and cycle indicator are high +output wb_we_o; // write enable output - 1 - write operation, 0 - read operation +output [2:0] wb_cti_o; // WB B3 - cycle type identifier +output [1:0] wb_bte_o; // WB B3 - burst type +output [3:0] wb_sel_o; // Byte select outputs +output [31:0] wb_adr_o; // WISHBONE address output +input [31:0] wb_dat_i; // WISHBONE interface input data bus +output [31:0] wb_dat_o; // WISHBONE interface output data bus +input wb_ack_i; // Acknowledge input - qualifies valid data on data output bus or received data on data input bus +input wb_rty_i; // retry input - signals from WISHBONE slave that cycle should be terminated and retried later +input wb_err_i; // Signals from WISHBONE slave that access resulted in an error + +reg wb_cyc_o; +reg wb_stb_o; +reg wb_we_o; +reg [2:0] wb_cti_o; +reg [1:0] wb_bte_o; +reg [3:0] wb_sel_o; +reg [31:0] wb_dat_o; + + + +/*########################################################################################################### +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + LOGIC, COUNTERS, STATE MACHINE and some control register bits + ============================================================= +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +###########################################################################################################*/ + +reg last_data_transferred ; // signal is set by STATE MACHINE after each complete transfere ! + +// wire for write attempt - 1 when PCI Target attempt to write and PCIW_FIFO has a write transaction ready +reg w_attempt; +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) + w_attempt <= #`FF_DELAY 1'b0; + else + begin + if (pciw_fifo_transaction_ready_in && ~pciw_fifo_empty_in) + w_attempt <= #`FF_DELAY 1'b1; + else + if (last_data_transferred) + w_attempt <= #`FF_DELAY 1'b0; + end +end + +// wire for read attempt - 1 when PCI Target is attempting a read and PCIR_FIFO is not full ! +// because of transaction ordering, PCI Master must not start read untill all writes are done -> at that +// moment PCIW_FIFO is empty !!! (when read is pending PCI Target will block new reads and writes) +wire r_attempt = ( pci_tar_read_request && !w_attempt && pciw_fifo_empty_in ) ; + +// Signal is used for reads on WB, when there is retry! +reg first_wb_data_access ; + +reg last_data_from_pciw_fifo ; // signal tells when there is last data in pciw_fifo +reg last_data_from_pciw_fifo_reg ; +reg last_data_to_pcir_fifo ; // signal tells when there will be last data for pcir_fifo + +// Logic used in State Machine logic implemented out of State Machine because of less delay! +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) + last_data_from_pciw_fifo <= #`FF_DELAY 1'b0 ; + else + begin + if ((pciw_fifo_renable_out) && + (pciw_fifo_control_in[`LAST_CTRL_BIT] || pciw_fifo_almost_empty_in)) // if last data is going to be transfered + last_data_from_pciw_fifo <= #`FF_DELAY 1'b1 ; // signal for last data from PCIW_FIFO + else + last_data_from_pciw_fifo <= #`FF_DELAY 1'b0 ; + end +end + + reg read_count_load; + reg read_count_enable; + + reg [(`PCIR_ADDR_LENGTH - 1):0] max_read_count ; + always@(pci_cache_line_size or cache_lsize_not_zero or pci_tar_cmd) + begin + if (cache_lsize_not_zero) + if ( (pci_cache_line_size >= `PCIR_DEPTH) || (~pci_tar_cmd[1] && ~pci_tar_cmd[0]) ) + // If cache line size is larger than FIFO or BC_MEM_READ_MUL command is performed! + max_read_count = `PCIR_DEPTH - 1'b1; + else + max_read_count = pci_cache_line_size ; + else + max_read_count = 1'b1; + end + + reg [(`PCIR_ADDR_LENGTH - 1):0] read_count ; + + // cache line bound indicator - it signals when data for one complete cacheline was read + wire read_bound_comb = ~|( { read_count[(`PCIR_ADDR_LENGTH - 1):2], read_count[0] } ) ; + + reg read_bound ; + always@(posedge wb_clock_in or posedge reset_in) + begin + if ( reset_in ) + read_bound <= #`FF_DELAY 1'b0 ; + else if (read_count_load) + read_bound <= #`FF_DELAY 1'b0 ; + else if ( read_count_enable ) + read_bound <= #`FF_DELAY read_bound_comb ; + end + + // down counter with load + always@(posedge reset_in or posedge wb_clock_in) + begin + if (reset_in) + read_count <= #`FF_DELAY 0 ; + else + if (read_count_load) + read_count <= #`FF_DELAY max_read_count ; + else + if (read_count_enable) + read_count <= #`FF_DELAY read_count - 1'b1 ; + end + +// Logic used in State Machine logic implemented out of State Machine because of less delay! +// definition of signal telling, when there is last data written into FIFO +always@(pci_tar_cmd or pci_tar_burst_ok or read_bound) +begin + // burst is OK for reads when there is ((MEM_READ_LN or MEM_READ_MUL) and AD[1:0]==2'b00) OR + // (MEM_READ and Prefetchable_IMAGE and AD[1:0]==2'b00) -> pci_tar_burst_ok + case ({pci_tar_cmd, pci_tar_burst_ok}) + {`BC_MEM_READ, 1'b1}, + {`BC_MEM_READ_LN, 1'b1} : + begin // when burst cycle + if (read_bound) + last_data_to_pcir_fifo = 1'b1 ; + else + last_data_to_pcir_fifo = 1'b0 ; + end + {`BC_MEM_READ_MUL, 1'b1} : + begin // when burst cycle + if (read_bound) + last_data_to_pcir_fifo = 1'b1 ; + else + last_data_to_pcir_fifo = 1'b0 ; + end + default : + // {`BC_IO_READ, 1'b0}, + // {`BC_IO_READ, 1'b1}, + // {`BC_MEM_READ, 1'b0}, + // {`BC_MEM_READ_LN, 1'b0}, + // {`BC_MEM_READ_MUL, 1'b0}: + begin // when single cycle + last_data_to_pcir_fifo = 1'b1 ; + end + endcase +end + +reg wait_for_wb_response ; + +`ifdef PCI_WBM_NO_RESPONSE_CNT_DISABLE +wire set_retry = 1'b0 ; + +`else +reg [3:0] wb_no_response_cnt ; +reg [3:0] wb_response_value ; +reg set_retry ; // + +// internal WB no response retry generator counter! +always@(posedge reset_in or posedge wb_clock_in) +begin + if (reset_in) + wb_no_response_cnt <= #`FF_DELAY 4'h0 ; + else + wb_no_response_cnt <= #`FF_DELAY wb_response_value ; +end +// internal WB no response retry generator logic +always@(wait_for_wb_response or wb_no_response_cnt) +begin + if (wb_no_response_cnt == 4'h8) // when there isn't response for 8 clocks, set internal retry + begin + wb_response_value = 4'h0 ; + set_retry = 1'b1 ; + end + else + begin + if (wait_for_wb_response) + wb_response_value = wb_no_response_cnt + 1'h1 ; // count clocks when no response + else + wb_response_value = 4'h0 ; + set_retry = 1'b0 ; + end +end +`endif + +wire retry = wb_rty_i || set_retry ; // retry signal - logic OR function between wb_rty_i and internal WB no response retry! +reg [7:0] rty_counter ; // output from retry counter +reg [7:0] rty_counter_in ; // input value - output value + 1 OR output value +reg rty_counter_almost_max_value ; // signal tells when retry counter riches maximum value - 1! +reg reset_rty_cnt ; // signal for asynchronous reset of retry counter after each complete transfere + +// sinchronous signal after each transfere and asynchronous signal 'reset_rty_cnt' after reset +// for reseting the retry counter +always@(posedge reset_in or posedge wb_clock_in) +begin + if (reset_in) + reset_rty_cnt <= #`FF_DELAY 1'b1 ; // asynchronous set when reset signal is active + else + reset_rty_cnt <= #`FF_DELAY wb_ack_i || wb_err_i || last_data_transferred ; // synchronous set after completed transfere +end + +// Retry counter register control +always@(posedge reset_in or posedge wb_clock_in) +begin + if (reset_in) + rty_counter <= #`FF_DELAY 8'h00 ; + else + begin + if (reset_rty_cnt) + rty_counter <= #`FF_DELAY 8'h00 ; + else if (retry) + rty_counter <= #`FF_DELAY rty_counter_in ; + end +end +// Retry counter logic +always@(rty_counter) +begin + if(rty_counter == `WB_RTY_CNT_MAX - 1'b1) // stop counting + begin + rty_counter_in = rty_counter ; + rty_counter_almost_max_value = 1'b1 ; + end + else + begin + rty_counter_in = rty_counter + 1'b1 ; // count up + rty_counter_almost_max_value = 1'b0 ; + end +end + +reg [31:0] addr_cnt_out ; // output value from address counter to WB ADDRESS output +reg [31:0] addr_cnt_in ; // input address value to address counter +reg addr_into_cnt ; // control signal for loading starting address into counter +reg addr_into_cnt_reg ; +reg addr_count ; // control signal for count enable +reg [3:0] bc_register ; // used when error occures during writes! + +// wb address counter register control +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) // reset counter + begin + addr_cnt_out <= #`FF_DELAY 32'h0000_0000 ; + bc_register <= #`FF_DELAY 4'h0 ; + addr_into_cnt_reg <= #`FF_DELAY 1'b0; + end + else + begin + addr_cnt_out <= #`FF_DELAY addr_cnt_in ; // count up or hold value depending on cache line counter logic + addr_into_cnt_reg <= #`FF_DELAY addr_into_cnt; + if (addr_into_cnt) + bc_register <= #`FF_DELAY pciw_fifo_cbe_in ; + end +end + +// when '1', the bus command is IO command - not supported commands are checked in pci_decoder modules +wire io_memory_bus_command = !pci_tar_cmd[3] && !pci_tar_cmd[2] ; + +// wb address counter logic +always@(addr_into_cnt or r_attempt or addr_count or pciw_fifo_addr_data_in or pci_tar_address or addr_cnt_out or + io_memory_bus_command) +begin + if (addr_into_cnt) // load starting address into counter + begin + if (r_attempt) + begin // if read request, then load read addresss from PCI Target + addr_cnt_in = {pci_tar_address[31:2], pci_tar_address[1] && io_memory_bus_command, + pci_tar_address[0] && io_memory_bus_command} ; + end + else + begin // if not read request, then load write address from PCIW_FIFO + addr_cnt_in = pciw_fifo_addr_data_in[31:0] ; + end + end + else + if (addr_count) + begin + addr_cnt_in = addr_cnt_out + 3'h4 ; // count up for 32-bit alligned address + end + else + begin + addr_cnt_in = addr_cnt_out ; + end +end + +reg retried ; // Signal is output value from FF and is set for one clock period after retried_d is set +reg retried_d ; // Signal is set whenever cycle is retried and is input to FF for delaying -> used in S_IDLE state +reg retried_write; +reg rty_i_delayed; // Dignal used for determinig the source of retry! + +reg first_data_is_burst ; // Signal is set in S_WRITE or S_READ states, when data transfere is burst! +reg first_data_is_burst_reg ; +wire burst_transfer ; // This signal is set when data transfere is burst and is reset with RESET or last data transfered +reg burst_chopped; // This signal is set when WB_SEL_O is changed during burst write transaction +reg burst_chopped_delayed; + +// FFs output signals tell, when there is first data out from FIFO (for BURST checking) +// and for delaying retried signal +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) // reset signals + begin + retried <= #`FF_DELAY 1'b0 ; + retried_write <= #`FF_DELAY 1'b0 ; + rty_i_delayed <= #`FF_DELAY 1'B0 ; + end + else + begin + retried <= #`FF_DELAY retried_d ; // delaying retried signal + retried_write <= #`FF_DELAY retried ; + rty_i_delayed <= #`FF_DELAY wb_rty_i ; + end +end + +// Determinig if first data is a part of BURST or just a single transfere! +always@(addr_into_cnt or r_attempt or pci_tar_burst_ok or max_read_count or + pciw_fifo_control_in or pciw_fifo_empty_in) +begin + if (addr_into_cnt) + begin + if (r_attempt) + begin + // burst is OK for reads when there is ((MEM_READ_LN or MEM_READ_MUL) and AD[1:0]==2'b00) OR + // (MEM_READ and Prefetchable_IMAGE and AD[1:0]==2'b00) -> pci_tar_burst_ok + if (pci_tar_burst_ok && (max_read_count != 8'h1)) + first_data_is_burst = 1'b1 ; + else + first_data_is_burst = 1'b0 ; + end + else + begin + first_data_is_burst = 1'b0 ; + end + end + else + first_data_is_burst = pciw_fifo_control_in[`BURST_BIT] && ~pciw_fifo_empty_in && + ~pciw_fifo_control_in[`LAST_CTRL_BIT] /*&& ~pciw_fifo_control_in[`DATA_ERROR_CTRL_BIT]*/; +end + +// FF for seting and reseting burst_transfer signal +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) + begin + burst_chopped <= #`FF_DELAY 1'b0; + burst_chopped_delayed <= #`FF_DELAY 1'b0; + first_data_is_burst_reg <= #`FF_DELAY 1'b0 ; + end + else + begin + if (pciw_fifo_transaction_ready_in) + begin + if (pciw_fifo_control_in[`DATA_ERROR_CTRL_BIT]) + burst_chopped <= #`FF_DELAY 1'b1; + else if (wb_ack_i || wb_err_i || wb_rty_i) + burst_chopped <= #`FF_DELAY 1'b0; + end + else + burst_chopped <= #`FF_DELAY 1'b0; + burst_chopped_delayed <= #`FF_DELAY burst_chopped; + if (last_data_transferred || first_data_is_burst) + first_data_is_burst_reg <= #`FF_DELAY ~last_data_transferred ; + end +end +assign burst_transfer = first_data_is_burst || first_data_is_burst_reg ; + +reg [(`WB_FSM_BITS - 1):0] c_state ; //current state register +reg [(`WB_FSM_BITS - 1):0] n_state ; //next state input to current state register + +//################################## +// WISHBONE B3 master state machine +//################################## + +// state machine register control and registered outputs (without wb_adr_o counter) +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) // reset state machine to S_IDLE state + begin + c_state <= #`FF_DELAY S_IDLE; + wb_cyc_o <= #`FF_DELAY 1'b0; + wb_stb_o <= #`FF_DELAY 1'b0; + wb_we_o <= #`FF_DELAY 1'b0; + wb_cti_o <= #`FF_DELAY 3'h2; + wb_bte_o <= #`FF_DELAY 2'h0; + wb_sel_o <= #`FF_DELAY 4'h0; + wb_dat_o <= #`FF_DELAY 32'h0; + pcir_fifo_data_out <= #`FF_DELAY 32'h0; + pcir_fifo_control_out <= #`FF_DELAY 4'h0; + pcir_fifo_wenable_out <= #`FF_DELAY 1'b0; + end + else + begin + c_state <= #`FF_DELAY n_state; + wb_bte_o <= #`FF_DELAY 2'h0; + case (n_state) // synthesis parallel_case full_case + S_WRITE: + begin + wb_cyc_o <= #`FF_DELAY ~addr_into_cnt; + wb_stb_o <= #`FF_DELAY ~addr_into_cnt; + wb_we_o <= #`FF_DELAY ~addr_into_cnt; + // if '1' then next burst BE is not equat to current one => burst is chopped into singles + // OR if last data is going to be transfered + if ((wb_stb_o && wb_ack_i) || addr_into_cnt_reg || (~wb_cyc_o && (retried || burst_chopped_delayed))) + begin + if (burst_transfer && ~pciw_fifo_control_in[`DATA_ERROR_CTRL_BIT] && + ~(pciw_fifo_renable_out && (pciw_fifo_control_in[`LAST_CTRL_BIT] || pciw_fifo_almost_empty_in))) + wb_cti_o <= #`FF_DELAY 3'h2; + else + wb_cti_o <= #`FF_DELAY 3'h7; + end + if ((pciw_fifo_renable_out && ~addr_into_cnt) || addr_into_cnt_reg) + begin + wb_sel_o <= #`FF_DELAY ~pciw_fifo_cbe_in; + wb_dat_o <= #`FF_DELAY pciw_fifo_addr_data_in; + end + end + S_WRITE_ERR_RTY: + begin + wb_cyc_o <= #`FF_DELAY 1'b0; + wb_stb_o <= #`FF_DELAY 1'b0; + wb_we_o <= #`FF_DELAY 1'b0; + wb_cti_o <= #`FF_DELAY 3'h2; + // stay the same as previous + //wb_sel_o <= #`FF_DELAY 4'h0; + //wb_dat_o <= #`FF_DELAY 32'h0; + end + S_READ: + begin + wb_cyc_o <= #`FF_DELAY ~addr_into_cnt; + wb_stb_o <= #`FF_DELAY ~addr_into_cnt; + wb_we_o <= #`FF_DELAY 1'b0; + if ((wb_stb_o && wb_ack_i) || addr_into_cnt_reg || (~wb_cyc_o && retried)) + begin + if (burst_transfer && ~read_bound_comb) + wb_cti_o <= #`FF_DELAY 3'h2; + else + wb_cti_o <= #`FF_DELAY 3'h7; + end + if (burst_transfer) + wb_sel_o <= #`FF_DELAY 4'hF; + else + wb_sel_o <= #`FF_DELAY ~pci_tar_be; + // no need to change att all + //wb_dat_o <= #`FF_DELAY 32'h0; + end + S_READ_RTY: + begin + wb_cyc_o <= #`FF_DELAY 1'b0; + wb_stb_o <= #`FF_DELAY 1'b0; + wb_we_o <= #`FF_DELAY 1'b0; + wb_cti_o <= #`FF_DELAY 3'h2; + // no need to change att all + //wb_sel_o <= #`FF_DELAY 4'h0; + //wb_dat_o <= #`FF_DELAY 32'h0; + end + S_TURN_ARROUND: + begin + wb_cyc_o <= #`FF_DELAY 1'b0; + wb_stb_o <= #`FF_DELAY 1'b0; + wb_we_o <= #`FF_DELAY 1'b0; + wb_cti_o <= #`FF_DELAY 3'h2; + // no need to change att all + //wb_sel_o <= #`FF_DELAY 4'h0; + //wb_dat_o <= #`FF_DELAY 32'h0; + end + default: // S_IDLE: + begin + wb_cyc_o <= #`FF_DELAY 1'b0; + wb_stb_o <= #`FF_DELAY 1'b0; + wb_we_o <= #`FF_DELAY 1'b0; + wb_cti_o <= #`FF_DELAY 3'h2; + // no need to change att all + //wb_sel_o <= #`FF_DELAY 4'h0; + //wb_dat_o <= #`FF_DELAY 32'h0; + end + endcase + pcir_fifo_data_out <= #`FF_DELAY wb_dat_i; + pcir_fifo_control_out <= #`FF_DELAY pcir_fifo_control ; + pcir_fifo_wenable_out <= #`FF_DELAY pcir_fifo_wenable ; + end +end + +assign wb_adr_o = addr_cnt_out ; + +// state machine logic +always@(c_state or + wb_ack_i or + wb_rty_i or + wb_err_i or + w_attempt or + r_attempt or + retried or + burst_chopped or + burst_chopped_delayed or + rty_i_delayed or + pci_tar_read_request or + rty_counter_almost_max_value or + set_retry or + last_data_to_pcir_fifo or + first_wb_data_access or + pciw_fifo_control_in or + pciw_fifo_empty_in or + burst_transfer or + last_data_from_pciw_fifo_reg + ) +begin + case (c_state) + S_IDLE: + begin + // Default values for signals not used in this state + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + addr_count = 1'b0 ; + read_count_enable = 1'b0 ; + pci_error_sig_out = 1'b0 ; + error_source_out = 1'b0 ; + retried_d = 1'b0 ; + last_data_transferred = 1'b0 ; + wb_read_done = 1'b0 ; + wait_for_wb_response = 1'b0 ; + write_rty_cnt_exp_out = 1'b0 ; + pci_error_sig_out = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; + case ({w_attempt, r_attempt, retried}) + 3'b101 : // Write request for PCIW_FIFO to WB bus transaction + begin // If there was retry, the same transaction must be initiated + pciw_fifo_renable = 1'b0 ; // the same data + addr_into_cnt = 1'b0 ; // the same address + read_count_load = 1'b0 ; // no need for cache line when there is write + n_state = S_WRITE ; + end + 3'b100 : // Write request for PCIW_FIFO to WB bus transaction + begin // If there is new transaction + if (burst_chopped_delayed) + begin + addr_into_cnt = 1'b0 ; // address must not be latched into address counter + pciw_fifo_renable = 1'b1 ; // first location is address (in FIFO), next will be data + end + else + begin + if (pciw_fifo_control_in[`ADDR_CTRL_BIT]) + addr_into_cnt = 1'b1 ; // address must be latched into address counter + else + addr_into_cnt = 1'b0 ; + pciw_fifo_renable = 1'b1 ; // first location is address (in FIFO), next will be data + end + read_count_load = 1'b0 ; // no need for cache line when there is write + n_state = S_WRITE ; + end + 3'b011 : // Read request from PCI Target for WB bus to PCIR_FIFO transaction + begin // If there was retry, the same transaction must be initiated + addr_into_cnt = 1'b0 ; // the same address + read_count_load = 1'b0 ; // cache line counter must not be changed for retried read + pciw_fifo_renable = 1'b0 ; // don't read from FIFO, when read transaction from WB to FIFO + n_state = S_READ ; + end + 3'b010 : // Read request from PCI Target for WB bus to PCIR_FIFO transaction + begin // If there is new transaction + addr_into_cnt = 1'b1 ; // address must be latched into counter from separate request bus + read_count_load = 1'b1 ; // cache line size must be latched into its counter + pciw_fifo_renable = 1'b0 ; // don't read from FIFO, when read transaction from WB to FIFO + n_state = S_READ ; + end + default : // stay in IDLE state + begin + pciw_fifo_renable = 1'b0 ; + addr_into_cnt = 1'b0 ; + read_count_load = 1'b0 ; + n_state = S_IDLE ; + end + endcase + end + S_WRITE: // WRITE from PCIW_FIFO to WB bus + begin + // Default values for signals not used in this state + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + addr_into_cnt = 1'b0 ; + read_count_load = 1'b0 ; + read_count_enable = 1'b0 ; + wb_read_done = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; + case ({wb_ack_i, wb_err_i, wb_rty_i}) + 3'b100 : // If writting of one data is acknowledged + begin + addr_count = 1'b1 ; // prepare next address if there will be burst + retried_d = 1'b0 ; // there was no retry + pci_error_sig_out = 1'b0 ; // there was no error + error_source_out = 1'b0 ; + write_rty_cnt_exp_out = 1'b0 ; // there was no retry + wait_for_wb_response = 1'b0 ; + // if last data was transfered ! + if (last_data_from_pciw_fifo_reg) + begin + n_state = S_TURN_ARROUND; + if (~pciw_fifo_empty_in) + pciw_fifo_renable = 1'b0 ; // prepare next value (address when new trans., data when burst tran.) + else + pciw_fifo_renable = 1'b0 ; + last_data_transferred = 1'b1 ; // signal for last data transfered + end + // next burst data has different byte enables ! + else if (burst_transfer && burst_chopped) + begin + n_state = S_IDLE ; + pciw_fifo_renable = 1'b0 ; // next value (address when new trans., data when burst tran.) + last_data_transferred = 1'b0 ; + end + else + begin + n_state = S_WRITE ; + pciw_fifo_renable = 1'b1 ; // prepare next value (address when new trans., data when burst tran.) + last_data_transferred = 1'b0 ; + end + end + 3'b010 : // If writting of one data is terminated with ERROR + begin + if (~pciw_fifo_empty_in) + pciw_fifo_renable = 1'b1 ; // prepare next value (address when new trans., data when cleaning FIFO) + else + pciw_fifo_renable = 1'b0 ; + addr_count = 1'b0 ; // no need for new address + retried_d = 1'b0 ; // there was no retry + last_data_transferred = 1'b1 ; // signal for last data transfered + pci_error_sig_out = 1'b1 ; // segnal for error reporting + error_source_out = 1'b0 ; // error source from other side of WB bus + write_rty_cnt_exp_out = 1'b0 ; // there was no retry + wait_for_wb_response = 1'b0 ; + if (last_data_from_pciw_fifo_reg) // if last data was transfered + n_state = S_TURN_ARROUND ; // go to S_TURN_ARROUND for new transfere + else // if there wasn't last data of transfere + n_state = S_WRITE_ERR_RTY ; // go here to clean this write transaction from PCIW_FIFO + end + 3'b001 : // If writting of one data is retried + begin + addr_count = 1'b0 ; + last_data_transferred = 1'b0 ; + retried_d = 1'b1 ; // there was a retry + wait_for_wb_response = 1'b0 ; + if(rty_counter_almost_max_value) // If retry counter reached maximum allowed value + begin + if (last_data_from_pciw_fifo_reg) // if last data was transfered + pciw_fifo_renable = 1'b0 ; + else // if there wasn't last data of transfere + pciw_fifo_renable = 1'b1 ; + n_state = S_WRITE_ERR_RTY ; // go here to clean this write transaction from PCIW_FIFO + write_rty_cnt_exp_out = 1'b1 ; // signal for reporting write counter expired + pci_error_sig_out = 1'b1 ; + error_source_out = 1'b1 ; // error ocuerd because of retry counter + end + else + begin + pciw_fifo_renable = 1'b0 ; + n_state = S_IDLE ; // go to S_IDLE state for retrying the transaction + write_rty_cnt_exp_out = 1'b0 ; // retry counter hasn't expired yet + pci_error_sig_out = 1'b0 ; + error_source_out = 1'b0 ; + end + end + default : + begin + addr_count = 1'b0 ; + last_data_transferred = 1'b0 ; + wait_for_wb_response = 1'b1 ; // wait for WB device to response (after 8 clocks RTY CNT is incremented) + error_source_out = 1'b0 ; // if error ocures, error source is from other WB bus side + if((rty_counter_almost_max_value)&&(set_retry)) // when no WB response and RTY CNT reached maximum allowed value + begin + retried_d = 1'b1 ; + if (last_data_from_pciw_fifo_reg) // if last data was transfered + pciw_fifo_renable = 1'b0 ; + else // if there wasn't last data of transfere + pciw_fifo_renable = 1'b1 ; + n_state = S_WRITE_ERR_RTY ; // go here to clean this write transaction from PCIW_FIFO + write_rty_cnt_exp_out = 1'b1 ; // signal for reporting write counter expired + pci_error_sig_out = 1'b1 ; // signal for error reporting + end + else + begin + pciw_fifo_renable = 1'b0 ; + retried_d = 1'b0 ; + n_state = S_WRITE ; // stay in S_WRITE state to wait WB to response + write_rty_cnt_exp_out = 1'b0 ; // retry counter hasn't expired yet + pci_error_sig_out = 1'b0 ; + end + end + endcase + end + S_WRITE_ERR_RTY: // Clean current write transaction from PCIW_FIFO if ERROR or Retry counter expired occures + begin + pciw_fifo_renable = !last_data_from_pciw_fifo_reg ; // put out next data (untill last data or FIFO empty) + last_data_transferred = 1'b1 ; // after exiting this state, negedge of this signal is used + // Default values for signals not used in this state + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + addr_into_cnt = 1'b0 ; + read_count_load = 1'b0 ; + read_count_enable = 1'b0 ; + addr_count = 1'b0 ; + pci_error_sig_out = 1'b0 ; + error_source_out = 1'b0 ; + retried_d = 1'b0 ; + wb_read_done = 1'b0 ; + write_rty_cnt_exp_out = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; + wait_for_wb_response = 1'b0 ; + // If last data is cleaned out from PCIW_FIFO + if (last_data_from_pciw_fifo_reg) + n_state = S_IDLE ; + else + n_state = S_WRITE_ERR_RTY ; // Clean until last data is cleaned out from FIFO + end + S_READ: // READ from WB bus to PCIR_FIFO + begin + // Default values for signals not used in this state + pciw_fifo_renable = 1'b0 ; + addr_into_cnt = 1'b0 ; + read_count_load = 1'b0 ; + pci_error_sig_out = 1'b0 ; + error_source_out = 1'b0 ; + write_rty_cnt_exp_out = 1'b0 ; + case ({wb_ack_i, wb_err_i, wb_rty_i}) + 3'b100 : // If reading of one data is acknowledged + begin + pcir_fifo_wenable = 1'b1 ; // enable writting data into PCIR_FIFO + addr_count = 1'b1 ; // prepare next address if there will be burst + read_count_enable = 1'b1 ; // decrease counter value for cache line size + retried_d = 1'b0 ; // there was no retry + read_rty_cnt_exp_out = 1'b0 ; // there was no retry + wait_for_wb_response = 1'b0 ; + // if last data was transfered + if (last_data_to_pcir_fifo) + begin + pcir_fifo_control[`LAST_CTRL_BIT] = 1'b1 ; // FIFO must indicate LAST data transfered + pcir_fifo_control[`DATA_ERROR_CTRL_BIT] = 1'b0 ; + pcir_fifo_control[`UNUSED_CTRL_BIT] = 1'b0 ; + pcir_fifo_control[`ADDR_CTRL_BIT] = 1'b0 ; + last_data_transferred = 1'b1 ; // signal for last data transfered + wb_read_done = 1'b1 ; // signal last data of read transaction for PCI Target + n_state = S_TURN_ARROUND ; + end + else // if not last data transfered + begin + pcir_fifo_control = 4'h0 ; // ZERO for control code + last_data_transferred = 1'b0 ; // not last data transfered + wb_read_done = 1'b0 ; // read is not done yet + n_state = S_READ ; + end + end + 3'b010 : // If reading of one data is terminated with ERROR + begin + pcir_fifo_wenable = 1'b1 ; // enable for writting to FIFO data with ERROR + addr_count = 1'b0 ; // no need for new address + pcir_fifo_control[`LAST_CTRL_BIT] = 1'b0 ; + pcir_fifo_control[`DATA_ERROR_CTRL_BIT] = 1'b1 ; // FIFO must indicate the DATA with ERROR + pcir_fifo_control[`UNUSED_CTRL_BIT] = 1'b0 ; + pcir_fifo_control[`ADDR_CTRL_BIT] = 1'b0 ; + last_data_transferred = 1'b1 ; // signal for last data transfered + wb_read_done = 1'b1 ; // signal last data of read transaction for PCI Target + read_count_enable = 1'b0 ; // no need for cache line, when error occures + n_state = S_TURN_ARROUND ; + retried_d = 1'b0 ; // there was no retry + wait_for_wb_response = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; // there was no retry + end + 3'b001 : // If reading of one data is retried + begin + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + addr_count = 1'b0 ; + read_count_enable = 1'b0 ; + wait_for_wb_response = 1'b0 ; + case ({first_wb_data_access, rty_counter_almost_max_value}) + 2'b10 : + begin // if first data of the cycle (CYC_O) is retried - after each retry CYC_O goes inactive + n_state = S_IDLE ; // go to S_IDLE state for retrying the transaction + read_rty_cnt_exp_out = 1'b0 ; // retry counter hasn't expired yet + last_data_transferred = 1'b0 ; + wb_read_done = 1'b0 ; + retried_d = 1'b1 ; // there was a retry + end + 2'b11 : + begin // if retry counter reached maximum value + n_state = S_READ_RTY ; // go here to wait for PCI Target to remove read request + read_rty_cnt_exp_out = 1'b1 ; // signal for reporting read counter expired + last_data_transferred = 1'b0 ; + wb_read_done = 1'b0 ; + retried_d = 1'b1 ; // there was a retry + end + default : // if retry occures after at least 1 data was transferred without breaking cycle (CYC_O inactive) + begin // then PCI device will retry access! + n_state = S_TURN_ARROUND ; // go to S_TURN_ARROUND state + read_rty_cnt_exp_out = 1'b0 ; // retry counter hasn't expired + last_data_transferred = 1'b1 ; + wb_read_done = 1'b1 ; + retried_d = 1'b0 ; // retry must not be retried, since there is not a first data + end + endcase + end + default : + begin + addr_count = 1'b0 ; + read_count_enable = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; + wait_for_wb_response = 1'b1 ; // wait for WB device to response (after 8 clocks RTY CNT is incremented) + if((rty_counter_almost_max_value)&&(set_retry)) // when no WB response and RTY CNT reached maximum allowed value + begin + retried_d = 1'b1 ; + n_state = S_TURN_ARROUND ; // go here to stop read request + pcir_fifo_wenable = 1'b1 ; + pcir_fifo_control[`LAST_CTRL_BIT] = 1'b0 ; + pcir_fifo_control[`DATA_ERROR_CTRL_BIT] = 1'b1 ; // FIFO must indicate the DATA with ERROR + pcir_fifo_control[`UNUSED_CTRL_BIT] = 1'b0 ; + pcir_fifo_control[`ADDR_CTRL_BIT] = 1'b0 ; + last_data_transferred = 1'b1 ; + wb_read_done = 1'b1 ; + end + else + begin + retried_d = 1'b0 ; + n_state = S_READ ; // stay in S_READ state to wait WB to response + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + last_data_transferred = 1'b0 ; + wb_read_done = 1'b0 ; + end + end + endcase + end + S_READ_RTY: // Wait for PCI Target to remove read request, when retry counter reaches maximum value! + begin + // Default values for signals not used in this state + pciw_fifo_renable = 1'b0 ; + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + addr_into_cnt = 1'b0 ; + read_count_load = 1'b0 ; + read_count_enable = 1'b0 ; + addr_count = 1'b0 ; + pci_error_sig_out = 1'b0 ; + error_source_out = 1'b0 ; + retried_d = 1'b0 ; + wb_read_done = 1'b0 ; + write_rty_cnt_exp_out = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; + wait_for_wb_response = 1'b0 ; + // wait for PCI Target to remove read request + if (pci_tar_read_request) + begin + n_state = S_READ_RTY ; // stay in this state until read request is removed + last_data_transferred = 1'b0 ; + end + else // when read request is removed + begin + n_state = S_IDLE ; + last_data_transferred = 1'b1 ; // when read request is removed, there is "last" data + end + end + // Turn arround cycle after writting to PCIR_FIFO (for correct data when reading from PCIW_FIFO) + default: // S_TURN_ARROUND: + begin + // Default values for signals not used in this state + pciw_fifo_renable = 1'b0 ; + pcir_fifo_wenable = 1'b0 ; + pcir_fifo_control = 4'h0 ; + addr_into_cnt = 1'b0 ; + read_count_load = 1'b0 ; + read_count_enable = 1'b0 ; + addr_count = 1'b0 ; + pci_error_sig_out = 1'b0 ; + error_source_out = 1'b0 ; + retried_d = 1'b0 ; + last_data_transferred = 1'b1 ; + wb_read_done = 1'b0 ; + write_rty_cnt_exp_out = 1'b0 ; + read_rty_cnt_exp_out = 1'b0 ; + wait_for_wb_response = 1'b0 ; + n_state = S_IDLE ; + end + endcase +end + +// Signal for retry monitor in state machine when there is read and first (or single) data access +wire ack_rty_response = wb_ack_i || wb_rty_i ; + +// Signal first_wb_data_access is set when no WB cycle present till end of first data access of WB cycle on WB bus +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) + first_wb_data_access = 1'b1 ; + else + begin + if (~wb_cyc_o) + first_wb_data_access = 1'b1 ; + else if (ack_rty_response) + first_wb_data_access = 1'b0 ; + end +end + +// Signals to FIFO +assign pcir_fifo_be_out = 4'hf ; // pci_tar_be ; + +// Signals to Conf. space +assign pci_error_bc = bc_register ; + + +always@(posedge wb_clock_in or posedge reset_in) +begin + if (reset_in) + wb_read_done_out <= #`FF_DELAY 1'b0 ; + else + wb_read_done_out <= #`FF_DELAY wb_read_done ; +end + +always@(pciw_fifo_renable or addr_into_cnt_reg or pciw_fifo_control_in or pciw_fifo_empty_in) +begin + pciw_fifo_renable_out = pciw_fifo_renable || addr_into_cnt_reg ; + last_data_from_pciw_fifo_reg = pciw_fifo_control_in[`ADDR_CTRL_BIT] || pciw_fifo_empty_in ; +end + + +endmodule +