module pci_target32_interface
(
    // system inputs
    clk_in,
    reset_in,

    // PCI Target side of INTERFACE
    address_in,
    addr_claim_out,
    bc_in,
    bc0_in,
    data_in,
    data_out,
    be_in,
    next_be_in,
    req_in,
    rdy_in,
    addr_phase_in,
    bckp_devsel_in,
    bckp_trdy_in,
    bckp_stop_in,
    last_reg_in,
    frame_reg_in,
    fetch_pcir_fifo_in,
    load_medium_reg_in,
    sel_fifo_mreg_in,
    sel_conf_fifo_in,
    load_to_pciw_fifo_in,
    load_to_conf_in,
    same_read_out,

	norm_access_to_config_out,
	read_completed_out,
	read_processing_out,
	target_abort_out,
	disconect_wo_data_out,
	disconect_w_data_out,
	pciw_fifo_full_out,
	pcir_fifo_data_err_out,
	wbw_fifo_empty_out,
	wbu_del_read_comp_pending_out,

	// Delayed synchronizacion module signals
	req_out,
    done_out,
    in_progress_out,
	req_req_pending_in,
    req_comp_pending_in,
	addr_out,
    be_out,
    we_out,
    bc_out,
    burst_ok_out,
	strd_addr_in,
	strd_bc_in,
    status_in,
    comp_flush_in,

	// FIFO signals
	pcir_fifo_renable_out,
	pcir_fifo_data_in,
	pcir_fifo_be_in,
	pcir_fifo_control_in,
	pcir_fifo_flush_out,
	pcir_fifo_almost_empty_in,
	pcir_fifo_empty_in,
	pciw_fifo_wenable_out,
	pciw_fifo_addr_data_out,
	pciw_fifo_cbe_out,
	pciw_fifo_control_out,
        pciw_fifo_three_left_in,
	pciw_fifo_two_left_in,
	pciw_fifo_almost_full_in,
	pciw_fifo_full_in,
	wbw_fifo_empty_in,
	wbu_del_read_comp_pending_in,

	// Configuration space signals
	conf_addr_out,
	conf_data_out,
	conf_data_in,
	conf_be_out,
	conf_we_out,
	conf_re_out,
	mem_enable_in,
	io_enable_in,
	mem_io_addr_space0_in,
	mem_io_addr_space1_in,
	mem_io_addr_space2_in,
	mem_io_addr_space3_in,
	mem_io_addr_space4_in,
	mem_io_addr_space5_in,
	pre_fetch_en0_in,
	pre_fetch_en1_in,
	pre_fetch_en2_in,
	pre_fetch_en3_in,
	pre_fetch_en4_in,
	pre_fetch_en5_in,
	pci_base_addr0_in,
	pci_base_addr1_in,
	pci_base_addr2_in,
	pci_base_addr3_in,
	pci_base_addr4_in,
	pci_base_addr5_in,
	pci_addr_mask0_in,
	pci_addr_mask1_in,
	pci_addr_mask2_in,
	pci_addr_mask3_in,
	pci_addr_mask4_in,
	pci_addr_mask5_in,
	pci_tran_addr0_in,
	pci_tran_addr1_in,
	pci_tran_addr2_in,
	pci_tran_addr3_in,
	pci_tran_addr4_in,
	pci_tran_addr5_in,
	addr_tran_en0_in,
	addr_tran_en1_in,
	addr_tran_en2_in,
	addr_tran_en3_in,
	addr_tran_en4_in,
	addr_tran_en5_in
) ;

`ifdef HOST
    `ifdef NO_CNF_IMAGE
        parameter pci_ba0_width = `PCI_NUM_OF_DEC_ADDR_LINES ;
    `else
        parameter pci_ba0_width = 20    ;
    `endif
`endif

`ifdef GUEST
    parameter pci_ba0_width = 20 ;
`endif

parameter pci_ba1_5_width = `PCI_NUM_OF_DEC_ADDR_LINES ;

/*==================================================================================================================
System inputs.
==================================================================================================================*/
// PCI side clock and reset
input   clk_in,
        reset_in ;


/*==================================================================================================================
Side of the PCI Target state machine
==================================================================================================================*/
// Data, byte enables, bus commands and address ports
input	[31:0]	address_in ;		// current request address input - registered
output          addr_claim_out ;	// current request address claim output
input	[3:0]   bc_in ;				// current request bus command input - registered
input			bc0_in ;			// current cycle RW signal
output	[31:0]  data_out ;			// for read operations - current dataphase data output
input   [31:0]  data_in ;			// for write operations - current request data input - registered
input   [3:0]	be_in ;				// current dataphase byte enable inputs - registered
input   [3:0]   next_be_in ;                    // next dataphase byte enable inputs - NOT registered
// Port connection control signals from PCI FSM
input         	req_in ;     		// Read is requested to WB master from PCI side
input         	rdy_in ;     		// DATA / ADDRESS selection from PCI side when read or write - registered
input			addr_phase_in ;		// Indicates address phase and also fast-back-to-back address phase - registered
input			bckp_devsel_in ;	// DEVSEL input (which is registered) equivalent
input			bckp_trdy_in ;		// TRDY input (which is registered) equivalent
input			bckp_stop_in ;		// STOP input (which is registered) equivalent
input		    last_reg_in ;		// Indicates last data phase - registered
input			frame_reg_in ;		// FRAME input signal - registered
input		    fetch_pcir_fifo_in ;// Read enable for PCIR_FIFO when when read is finishen on WB side
input		    load_medium_reg_in ;// Load data from PCIR_FIFO to medium register (first data must be prepared on time)
input		    sel_fifo_mreg_in ;	// Read data selection between PCIR_FIFO and medium register
input		    sel_conf_fifo_in ;	// Read data selection between Configuration registers and "FIFO"
input		    load_to_pciw_fifo_in ;// Write enable to PCIW_FIFO
input		    load_to_conf_in ;	// Write enable to Configuration space registers


/*==================================================================================================================
Status outputs to PCI side (FSM)
==================================================================================================================*/
output			same_read_out ;				// Indicates the same read request (important when read is finished on WB side)
output			norm_access_to_config_out ;	// Indicates the access to Configuration space with MEMORY commands
output			read_completed_out ;		// Indicates that read request is completed on WB side
output			read_processing_out ;		// Indicates that read request is processing on WB side
output			target_abort_out ;			// Indicates target abort termination
output			disconect_wo_data_out ;		// Indicates disconnect without data termination
output			disconect_w_data_out ;		// Indicates disconnect with data termination
output			pciw_fifo_full_out ;		// Indicates that write PCIW_FIFO is full
output			pcir_fifo_data_err_out ;	// Indicates data error on current data read from PCIR_FIFO
output			wbw_fifo_empty_out ;		// Indicates that WB SLAVE has no data to be written to PCI bus
output			wbu_del_read_comp_pending_out ; // Indicates that WB Unit has a delayed read poending!

/*==================================================================================================================
Read request interface through Delayed sinchronization module to WB Master
==================================================================================================================*/
// request, completion, done and progress indicator outputs for delayed_sync module where they are synchronized
output			req_out,           	// request qualifier - when 1 it indicates that valid data is provided on outputs
      			done_out,          	// done output - when 1 indicates that PCI Target has completed a cycle on its bus
      			in_progress_out ;  	// out progress indicator - indicates that current completion is in progress on
									//   PCI Target side
// pending indication inputs - PCI Target side must know about requests and completions
input			req_req_pending_in ; 	// request pending input for PCI Target side
input   		req_comp_pending_in ;	// completion pending input for PCI Target side - it indicates when completion
										//   is ready for completing on PCI Target bus
// various data outputs - PCI Target sets address, bus command, byte enables, write enable and burst
output	[31:0]	addr_out ;   // address bus output
output	[3:0]	be_out ;     // byte enable output
output	     	we_out ;     // write enable output - read/write request indication 1 = write request / 0 = read request
output	[3:0]	bc_out ;     // bus command output
output		 	burst_ok_out ;  // pre-fetch enable & burst read - qualifies pre-fetch for access to current image space

// completion side signals encoded termination status - 0 = normal completion / 1 = error terminated completion
input	[31:0]	strd_addr_in ;	// Stored requested read access address
input	[3:0]	strd_bc_in ;	// Stored requested read access bus command
input			status_in ;  	// Error status reported - NOT USED because FIFO control bits determin data error status
input		    comp_flush_in ;	// If completition counter (2^16 clk periods) has expired, PCIR_FIFO must flush data


/*==================================================================================================================
PCIR_PCIW_FIFO signals from pci side
==================================================================================================================*/
// PCIR_FIFO control signals used for fetching data from PCIR_FIFO
output			pcir_fifo_renable_out ;			// read enable output to PCIR_FIFO
input	[31:0]	pcir_fifo_data_in ;				// data input from PCIR_FIFO
input	[3:0]	pcir_fifo_be_in ;				// byte enable input from PCIR_FIFO
input	[3:0]	pcir_fifo_control_in ;			// control signals input from PCIR_FIFO
output			pcir_fifo_flush_out ;			// flush PCIR_FIFO
input			pcir_fifo_almost_empty_in ;		// almost empty indicator from PCIR_FIFO
input			pcir_fifo_empty_in ;			// empty indicator

// PCIW_FIFO control signals used for sinking data into PCIW_FIFO and status monitoring
output			pciw_fifo_wenable_out ;		// write enable output to PCIW_FIFO
wire            pciw_fifo_wenable ; // not registered we
output	[31:0]	pciw_fifo_addr_data_out ;	// address / data output signals to PCIW_FIFO
output	[3:0]	pciw_fifo_cbe_out ;			// command / byte enable signals to PCIW_FIFO
output	[3:0]	pciw_fifo_control_out ;		// control signals to PCIW_FIFO
input           pciw_fifo_three_left_in ;       // three data spaces left in PCIW_FIFO
input           pciw_fifo_two_left_in ;		// two data spaces left in PCIW_FIFO
input			pciw_fifo_almost_full_in ;	// almost full indicator from PCIW_FIFO
input			pciw_fifo_full_in ;			// full indicator from PCIW_FIFO

// WBW_FIFO empy control signal used when delayed read is complete in PCIR_FIFO
input			wbw_fifo_empty_in ;			// empty indicator from WBW_FIFO
input			wbu_del_read_comp_pending_in ; // delayed read pending indicator from WB Unit


/*==================================================================================================================
Configuration space signals - from and to registers
==================================================================================================================*/
// BUS for reading and writing to configuration space registers
output	[11:0]	conf_addr_out ;	// address to configuration space when there is access to it
output	[31:0]	conf_data_out ;	// data to configuration space - for writing to registers
input	[31:0]	conf_data_in ;	// data from configuration space - for reading from registers
output	[3:0]	conf_be_out ;	// byte enables used for correct writing to configuration space
output			conf_we_out ;	// write enable control signal - 1 for writing / 0 for nothing
output			conf_re_out ;	// read enable control signal - 1 for reading / 0 for nothing

// Inputs for image control registers
input			mem_enable_in ;	// allowed access to memory mapped image
input			io_enable_in ;	// allowed access to io mapped image

// Inputs needed for determining if image is assigned to memory or io space with pre-fetch and address translation
input			mem_io_addr_space0_in ;	// bit-0 in pci_base_addr0 register
input			mem_io_addr_space1_in ;	// bit-0 in pci_base_addr1 register
input			mem_io_addr_space2_in ;	// bit-0 in pci_base_addr2 register
input			mem_io_addr_space3_in ;	// bit-0 in pci_base_addr3 register
input			mem_io_addr_space4_in ;	// bit-0 in pci_base_addr4 register
input			mem_io_addr_space5_in ;	// bit-0 in pci_base_addr5 register
input			pre_fetch_en0_in ;	// bit-1 in pci_image_ctr0 register
input			pre_fetch_en1_in ;	// bit-1 in pci_image_ctr1 register
input			pre_fetch_en2_in ;	// bit-1 in pci_image_ctr2 register
input			pre_fetch_en3_in ;	// bit-1 in pci_image_ctr3 register
input			pre_fetch_en4_in ;	// bit-1 in pci_image_ctr4 register
input			pre_fetch_en5_in ;	// bit-1 in pci_image_ctr5 register

// Input from image registers - register values needed for decoder to work properly
input	[pci_ba0_width   - 1:0]	pci_base_addr0_in ;	// base address from base address register
input	[pci_ba1_5_width - 1:0]	pci_base_addr1_in ; // base address from base address register
input	[pci_ba1_5_width - 1:0]	pci_base_addr2_in ; // base address from base address register
input	[pci_ba1_5_width - 1:0]	pci_base_addr3_in ; // base address from base address register
input	[pci_ba1_5_width - 1:0]	pci_base_addr4_in ; // base address from base address register
input	[pci_ba1_5_width - 1:0]	pci_base_addr5_in ; // base address from base address register
input	[pci_ba1_5_width - 1:0]	pci_addr_mask0_in ; // masking of base address from address mask register
input	[pci_ba1_5_width - 1:0]	pci_addr_mask1_in ; // masking of base address from address mask register
input	[pci_ba1_5_width - 1:0]	pci_addr_mask2_in ; // masking of base address from address mask register
input	[pci_ba1_5_width - 1:0]	pci_addr_mask3_in ; // masking of base address from address mask register
input	[pci_ba1_5_width - 1:0]	pci_addr_mask4_in ; // masking of base address from address mask register
input	[pci_ba1_5_width - 1:0]	pci_addr_mask5_in ; // masking of base address from address mask register
input	[pci_ba1_5_width - 1:0]	pci_tran_addr0_in ; // translation address from address translation register
input	[pci_ba1_5_width - 1:0]	pci_tran_addr1_in ; // translation address from address translation register
input	[pci_ba1_5_width - 1:0]	pci_tran_addr2_in ; // translation address from address translation register
input	[pci_ba1_5_width - 1:0]	pci_tran_addr3_in ; // translation address from address translation register
input	[pci_ba1_5_width - 1:0]	pci_tran_addr4_in ; // translation address from address translation register
input	[pci_ba1_5_width - 1:0]	pci_tran_addr5_in ; // translation address from address translation register

input			addr_tran_en0_in ;	// address translation enable bit
input			addr_tran_en1_in ;	// address translation enable bit
input			addr_tran_en2_in ;	// address translation enable bit
input			addr_tran_en3_in ;	// address translation enable bit
input			addr_tran_en4_in ;	// address translation enable bit
input			addr_tran_en5_in ;	// address translation enable bit

/*==================================================================================================================
END of input / output PORT DEFINITONS !!!
==================================================================================================================*/

// address output from address multiplexer
reg		[31:0]	address ;
// prefetch enable for access to selected image space
reg				pre_fetch_en ;

// Input addresses and image hits from address decoders - addresses are multiplexed to address
`ifdef			HOST
	`ifdef		NO_CNF_IMAGE
		`ifdef	PCI_IMAGE0	// if PCI bridge is HOST and IMAGE0 is assigned as general image space
wire			hit0_in ;
wire	[31:0]	address0_in ;
wire			pre_fetch_en0 = pre_fetch_en0_in ;
		`else
wire			hit0_in		= 1'b0 ;
wire	[31:0]	address0_in	= 32'h0 ;
wire			pre_fetch_en0 = 1'b0 ;
		`endif
	`else
wire			hit0_in ;
wire	[31:0]	address0_in ;
wire			pre_fetch_en0 = pre_fetch_en0_in ;
	`endif
`else // GUEST
wire			hit0_in ;
wire	[31:0]	address0_in ;
wire			pre_fetch_en0 = pre_fetch_en0_in ;
`endif

wire			hit1_in ;
wire	[31:0]	address1_in ;
wire			pre_fetch_en1 = pre_fetch_en1_in ;

`ifdef		PCI_IMAGE2
wire			hit2_in ;
wire	[31:0]	address2_in ;
wire			pre_fetch_en2 = pre_fetch_en2_in ;
`else
wire			hit2_in		= 1'b0 ;
wire	[31:0]	address2_in	= 32'h0 ;
wire			pre_fetch_en2 = 1'b0 ;
`endif

`ifdef		PCI_IMAGE3
wire			hit3_in ;
wire	[31:0]	address3_in ;
wire			pre_fetch_en3 = pre_fetch_en3_in ;
`else
wire			hit3_in		= 1'b0 ;
wire	[31:0]	address3_in	= 32'h0 ;
wire			pre_fetch_en3 = 1'b0 ;
`endif

`ifdef		PCI_IMAGE4
wire			hit4_in ;
wire	[31:0]	address4_in ;
wire			pre_fetch_en4 = pre_fetch_en4_in ;
`else
wire			hit4_in		= 1'b0 ;
wire	[31:0]	address4_in	= 32'h0 ;
wire			pre_fetch_en4 = 1'b0 ;
`endif

`ifdef		PCI_IMAGE5
wire			hit5_in ;
wire	[31:0]	address5_in ;
wire			pre_fetch_en5 = pre_fetch_en5_in ;
`else
wire			hit5_in		= 1'b0 ;
wire	[31:0]	address5_in	= 32'h0 ;
wire			pre_fetch_en5 = 1'b0 ;
`endif

// Include address decoders
`ifdef			HOST
	`ifdef		NO_CNF_IMAGE
		`ifdef	PCI_IMAGE0	// if PCI bridge is HOST and IMAGE0 is assigned as general image space
	pci_pci_decoder   #(pci_ba0_width) decoder0
				   (.hit			(hit0_in),
					.addr_out		(address0_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr0_in),
					.mask_addr		(pci_addr_mask0_in),
					.tran_addr		(pci_tran_addr0_in),
					.at_en			(addr_tran_en0_in),
					.mem_io_space	(mem_io_addr_space0_in),
					.mem_en			(mem_enable_in),
					.io_en			(io_enable_in)
					) ;
		`endif
	`else
	pci_pci_decoder   #(pci_ba0_width) decoder0
				   (.hit			(hit0_in),
					.addr_out		(address0_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr0_in),
					.mask_addr		({pci_ba0_width{1'b1}}),
					.tran_addr		({pci_ba0_width{1'b0}}),
					.at_en			(1'b0),
					.mem_io_space	(1'b0),
					.mem_en			(mem_enable_in),
					.io_en			(1'b0)
					) ;
	`endif
`else // GUEST
	pci_pci_decoder   #(pci_ba0_width) decoder0
				   (.hit			(hit0_in),
					.addr_out		(address0_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr0_in),
					.mask_addr		({pci_ba0_width{1'b1}}),
					.tran_addr		({pci_ba0_width{1'b0}}),
					.at_en			(1'b0),
					.mem_io_space	(1'b0),
					.mem_en			(mem_enable_in),
					.io_en			(1'b0)
					) ;
`endif
	pci_pci_decoder   #(`PCI_NUM_OF_DEC_ADDR_LINES) decoder1
				   (.hit			(hit1_in),
					.addr_out		(address1_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr1_in),
					.mask_addr		(pci_addr_mask1_in),
					.tran_addr		(pci_tran_addr1_in),
					.at_en			(addr_tran_en1_in),
					.mem_io_space	(mem_io_addr_space1_in),
					.mem_en			(mem_enable_in),
					.io_en			(io_enable_in)
					) ;
`ifdef		PCI_IMAGE2
	pci_pci_decoder   #(`PCI_NUM_OF_DEC_ADDR_LINES) decoder2
				   (.hit			(hit2_in),
					.addr_out		(address2_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr2_in),
					.mask_addr		(pci_addr_mask2_in),
					.tran_addr		(pci_tran_addr2_in),
					.at_en			(addr_tran_en2_in),
					.mem_io_space	(mem_io_addr_space2_in),
					.mem_en			(mem_enable_in),
					.io_en			(io_enable_in)
					) ;
`endif
`ifdef		PCI_IMAGE3
	pci_pci_decoder   #(`PCI_NUM_OF_DEC_ADDR_LINES) decoder3
				   (.hit			(hit3_in),
					.addr_out		(address3_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr3_in),
					.mask_addr		(pci_addr_mask3_in),
					.tran_addr		(pci_tran_addr3_in),
					.at_en			(addr_tran_en3_in),
					.mem_io_space	(mem_io_addr_space3_in),
					.mem_en			(mem_enable_in),
					.io_en			(io_enable_in)
					) ;
`endif
`ifdef		PCI_IMAGE4
	pci_pci_decoder   #(`PCI_NUM_OF_DEC_ADDR_LINES) decoder4
				   (.hit			(hit4_in),
					.addr_out		(address4_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr4_in),
					.mask_addr		(pci_addr_mask4_in),
					.tran_addr		(pci_tran_addr4_in),
					.at_en			(addr_tran_en4_in),
					.mem_io_space	(mem_io_addr_space4_in),
					.mem_en			(mem_enable_in),
					.io_en			(io_enable_in)
					) ;
`endif
`ifdef		PCI_IMAGE5
	pci_pci_decoder   #(`PCI_NUM_OF_DEC_ADDR_LINES) decoder5
				   (.hit			(hit5_in),
					.addr_out		(address5_in),
					.addr_in		(address_in),
					.bc_in			(bc_in),
					.base_addr		(pci_base_addr5_in),
					.mask_addr		(pci_addr_mask5_in),
					.tran_addr		(pci_tran_addr5_in),
					.at_en			(addr_tran_en5_in),
					.mem_io_space	(mem_io_addr_space5_in),
					.mem_en			(mem_enable_in),
					.io_en			(io_enable_in)
					) ;
`endif

// Internal signals for image hit determination
reg				addr_claim ;// address claim signal is asinchronous set for addr_claim_out signal to PCI Target SM

// Determining if image 0 is assigned to configuration space or as normal pci to wb access!
//   if normal access is allowed to configuration space, then hit0 is hit0_conf
`ifdef		HOST
	`ifdef	NO_CNF_IMAGE
			parameter	hit0_conf = 1'b0 ;
	`else
			parameter	hit0_conf = 1'b1 ;	// if normal access is allowed to configuration space, then hit0 is hit0_conf
	`endif
`else // GUEST
			parameter	hit0_conf = 1'b1 ;	// if normal access is allowed to configuration space, then hit0 is hit0_conf
`endif

// Logic with address mux, determining if address is still in the same image space and if it is prefetced or not
always@(hit5_in or     hit4_in or     hit3_in or     hit2_in or     hit1_in or     hit0_in or
		address5_in or address4_in or address3_in or address2_in or address1_in or address0_in or
		pre_fetch_en5 or
		pre_fetch_en4 or
		pre_fetch_en3 or
		pre_fetch_en2 or
		pre_fetch_en1 or
		pre_fetch_en0
		)
begin
	addr_claim <= (hit5_in || hit4_in) || (hit3_in || hit2_in || hit1_in || hit0_in) ;
	case ({hit5_in, hit4_in, hit3_in, hit2_in, hit0_in})
	5'b10000 :
	begin
		address <= address5_in ;
		pre_fetch_en <= pre_fetch_en5 ;
	end
	5'b01000 :
	begin
		address <= address4_in ;
		pre_fetch_en <= pre_fetch_en4 ;
	end
	5'b00100 :
	begin
		address <= address3_in ;
		pre_fetch_en <= pre_fetch_en3 ;
	end
	5'b00010 :
	begin
		address <= address2_in ;
		pre_fetch_en <= pre_fetch_en2 ;
	end
	5'b00001 :
	begin
		address <= address0_in ;
		pre_fetch_en <= pre_fetch_en0 ;
	end
	default	: // IMAGE 1 is always included into PCI bridge
	begin
		address <= address1_in ;
		pre_fetch_en <= pre_fetch_en1 ;
	end
	endcase
end

// Address claim output to PCI Target SM
assign	addr_claim_out = addr_claim ;

reg		[31:0]	norm_address ;		// stored normal address (decoded and translated) for access to WB
reg				norm_prf_en ;		// stored pre-fetch enable
reg		[3:0]	norm_bc ;			// stored bus-command
reg				same_read_reg ;		// stored SAME_READ information
reg				target_rd ;		// delayed registered TRDY output equivalent signal

always@(posedge clk_in or posedge reset_in)
begin
    if (reset_in)
	begin
		norm_address <= #`FF_DELAY 32'h0000_0000 ;
		norm_prf_en <= #`FF_DELAY 1'b0 ;
		norm_bc <= #`FF_DELAY 4'h0 ;
		same_read_reg <= #`FF_DELAY 1'b0 ;
	end
	else
	begin
		if (addr_phase_in)
		begin
			norm_address <= #`FF_DELAY address ;
			norm_prf_en <= #`FF_DELAY pre_fetch_en ;
			norm_bc <= #`FF_DELAY bc_in ;
			same_read_reg <= #`FF_DELAY same_read_out ;
		end
	end
end

`ifdef		HOST
  `ifdef	NO_CNF_IMAGE
			reg		 [1:0]	strd_address ;		// stored INPUT address for accessing Configuration space registers
  `else
			reg		[11:0]	strd_address ;		// stored INPUT address for accessing Configuration space registers
  `endif
`else
			reg		[11:0]	strd_address ;		// stored INPUT address for accessing Configuration space registers
`endif
always@(posedge clk_in or posedge reset_in)
begin
    if (reset_in)
	begin
		strd_address <= #`FF_DELAY 0 ;
	end
	else
	begin
		if (addr_phase_in)
		begin
`ifdef		HOST
  `ifdef	NO_CNF_IMAGE
			strd_address <= #`FF_DELAY address_in[1:0] ;
  `else
			strd_address <= #`FF_DELAY address_in[11:0] ;
  `endif
`else
			strd_address <= #`FF_DELAY address_in[11:0] ;
`endif
		end
	end
end

always@(posedge clk_in or posedge reset_in)
begin
    if (reset_in)
	begin
		target_rd		<= #`FF_DELAY 1'b0 ;
	end
	else
	begin
		if (same_read_reg && !bckp_trdy_in)
			target_rd	<= #`FF_DELAY 1'b1 ;// Signal indicates when target ready is deaserted on PCI bus
		else if (same_read_reg && bckp_devsel_in && !bckp_stop_in)
			target_rd	<= #`FF_DELAY 1'b1 ;// Signal indicates when target ready is deaserted on PCI bus
		else if ((!same_read_reg) || (last_reg_in && target_rd))
			target_rd	<= #`FF_DELAY 1'b0 ;// Signal indicates when target ready is deaserted on PCI bus
	end
end
// '1' indicates asserted TRDY signal when same read operation is performed
wire	target_rd_completed	= target_rd ;

reg				same_read_request ;

// When delayed read is completed on WB, addres and bc must be compered, if there is the same read request
always@(address or strd_addr_in or bc_in or strd_bc_in)
begin
	if ((address == strd_addr_in) & (bc_in == strd_bc_in))
		same_read_request <= 1'b1 ;
	else
		same_read_request <= 1'b0 ;
end

assign	same_read_out = (same_read_request) ; // && ~pcir_fifo_empty_in) ;

// Signals for byte enable checking
reg				addr_burst_ok ;
reg				io_be_ok ;

// Byte enable checking for IO, MEMORY and CONFIGURATION spaces - be_in is active low!
always@(strd_address or be_in)
begin
	case (strd_address[1:0])
	2'b11 :
	begin
		addr_burst_ok <= 1'b0 ;
		io_be_ok <= (be_in[2] && be_in[1] && be_in[0]) ; // only be3 can be active
	end
	2'b10 :
	begin
		addr_burst_ok <= 1'b0 ;
		io_be_ok <= (~be_in[2] && be_in[1] && be_in[0]) || (be_in[3] && be_in[2] && be_in[1] && be_in[0]) ;
	end
	2'b01 :
	begin
		addr_burst_ok <= 1'b0 ;
		io_be_ok <= (~be_in[1] && be_in[0]) || (be_in[3] && be_in[2] && be_in[1] && be_in[0]) ;
	end
	default :	// 2'b00
	begin
		addr_burst_ok <= 1'b1 ;
		io_be_ok <= (~be_in[0]) || (be_in[3] && be_in[2] && be_in[1] && be_in[0]) ;
	end
	endcase
end

wire calc_target_abort = (norm_bc[3:1] == `BC_IO_RW) ? !io_be_ok : 1'b0 ;

wire [3:0]	pcir_fifo_control_input = pcir_fifo_empty_in ? 4'h0 : pcir_fifo_control_in ;

// Medium registers for data and control busses from PCIR_FIFO
reg		[31:0]	pcir_fifo_data_reg ;
reg		[3:0]	pcir_fifo_ctrl_reg ;

always@(posedge clk_in or posedge reset_in)
begin
    if (reset_in)
    begin
    	pcir_fifo_data_reg <= #`FF_DELAY 32'h0000_0000 ;
    	pcir_fifo_ctrl_reg <=  #`FF_DELAY 4'h0 ;
    end
    else
    begin
    	if (load_medium_reg_in)
    	begin
    		pcir_fifo_data_reg <= #`FF_DELAY pcir_fifo_data_in ;
    		pcir_fifo_ctrl_reg <= #`FF_DELAY pcir_fifo_control_input ;
    	end
    end
end

// when disconnect is signalled, the next data written to fifo will be the last
// also when this happens, disconnect must stay asserted until last data is written to the fifo
reg keep_desconnect_wo_data_set ;

// selecting "fifo data" from medium registers or from PCIR_FIFO
wire [31:0]	pcir_fifo_data = (sel_fifo_mreg_in && !pcir_fifo_empty_in) ? pcir_fifo_data_in : pcir_fifo_data_reg ;
wire [3:0]	pcir_fifo_ctrl = (sel_fifo_mreg_in && !pcir_fifo_empty_in) ? pcir_fifo_control_input : pcir_fifo_ctrl_reg ;

// signal assignments to PCI Target FSM
assign	read_completed_out = req_comp_pending_in ; // completion pending input for requesting side of the bridge
assign	read_processing_out = req_req_pending_in ; // request pending input for requesting side
  // when '1', the bus command is IO command - not supported commands are checked in pci_decoder modules
  wire	io_memory_bus_command = !norm_bc[3] && !norm_bc[2] ;
assign	disconect_wo_data_out = (
	((/*pcir_fifo_ctrl[`LAST_CTRL_BIT] ||*/ pcir_fifo_empty_in || ~burst_ok_out/*addr_burst_ok*/ || io_memory_bus_command) && 
		~bc0_in && ~frame_reg_in) ||
	((pciw_fifo_full_in || pciw_fifo_almost_full_in || keep_desconnect_wo_data_set || pciw_fifo_two_left_in || 
                (pciw_fifo_three_left_in && pciw_fifo_wenable) || ~addr_burst_ok || io_memory_bus_command) && 
		bc0_in && ~frame_reg_in)
								) ;
assign	disconect_w_data_out =	(
	( burst_ok_out  && !io_memory_bus_command && ~bc0_in ) || 
	( addr_burst_ok && !io_memory_bus_command && bc0_in )
								) ;
assign	target_abort_out = ( ~addr_phase_in && calc_target_abort ) ;

`ifdef		HOST
	`ifdef	NO_CNF_IMAGE
			// signal assignments to PCI Target FSM
			assign	norm_access_to_config_out = 1'b0 ;
			// control signal assignments to read request sinchronization module
			assign	done_out =  (target_rd_completed && last_reg_in) ;
			assign	in_progress_out = (same_read_reg && ~bckp_trdy_in) ;
			// signal used for PCIR_FIFO flush (with comp_flush_in signal)
			wire	pcir_fifo_flush = (target_rd_completed && last_reg_in && ~pcir_fifo_empty_in) ;
	`else
			// signal assignments to PCI Target FSM
			assign	norm_access_to_config_out = (hit0_in && hit0_conf) ;
			// control signal assignments to read request sinchronization module
			assign	done_out =  (~sel_conf_fifo_in && target_rd_completed && last_reg_in) ;
			assign	in_progress_out = (~sel_conf_fifo_in && same_read_reg && ~bckp_trdy_in) ;
			// signal used for PCIR_FIFO flush (with comp_flush_in signal)
			wire	pcir_fifo_flush = (~sel_conf_fifo_in && target_rd_completed && last_reg_in && ~pcir_fifo_empty_in) ;
	`endif
`else
			// signal assignments to PCI Target FSM
			assign	norm_access_to_config_out = (hit0_in && hit0_conf) ;
			// control signal assignments to read request sinchronization module
			assign	done_out =  (~sel_conf_fifo_in && target_rd_completed && last_reg_in) ;
			assign	in_progress_out = (~sel_conf_fifo_in && same_read_reg && ~bckp_trdy_in) ;
			// signal used for PCIR_FIFO flush (with comp_flush_in signal)
			wire	pcir_fifo_flush = (~sel_conf_fifo_in && target_rd_completed && last_reg_in && ~pcir_fifo_empty_in) ;
`endif

// flush signal for PCIR_FIFO must be registered, since it asinchronously resets some status registers
wire		pcir_fifo_flush_reg ;
pci_async_reset_flop async_reset_as_pcir_flush
(
    .data_in        	  (comp_flush_in || pcir_fifo_flush),
    .clk_in         	  (clk_in),
    .async_reset_data_out (pcir_fifo_flush_reg),
    .reset_in    		  (reset_in)
) ;

always@(posedge clk_in or posedge reset_in)
begin
    if (reset_in)
        keep_desconnect_wo_data_set     <= #1 1'b0 ;
    else if (keep_desconnect_wo_data_set && pciw_fifo_wenable)
        keep_desconnect_wo_data_set     <= #1 1'b0 ;
    else if (pciw_fifo_wenable && disconect_wo_data_out)
        keep_desconnect_wo_data_set     <= #1 1'b1 ;
end


// signal assignments from fifo to PCI Target FSM
assign	wbw_fifo_empty_out = wbw_fifo_empty_in ;
assign	wbu_del_read_comp_pending_out = wbu_del_read_comp_pending_in ;
assign	pciw_fifo_full_out = (pciw_fifo_full_in || pciw_fifo_almost_full_in || pciw_fifo_two_left_in || pciw_fifo_three_left_in) ;
assign	pcir_fifo_data_err_out = pcir_fifo_ctrl[`DATA_ERROR_CTRL_BIT] && !sel_conf_fifo_in ;
// signal assignments to PCIR FIFO fifo
assign	pcir_fifo_flush_out							= pcir_fifo_flush_reg ;
assign	pcir_fifo_renable_out						= fetch_pcir_fifo_in && !pcir_fifo_empty_in ;

// signal assignments to PCIW FIFO
reg          pciw_fifo_wenable_out;
assign       pciw_fifo_wenable = load_to_pciw_fifo_in ;
reg   [3:0]  pciw_fifo_control_out;
reg  [31:0]  pciw_fifo_addr_data_out;
reg   [3:0]  pciw_fifo_cbe_out;
always@(posedge clk_in or posedge reset_in)
begin
    if (reset_in)
    begin
        pciw_fifo_wenable_out   <= #1 1'b0;
        pciw_fifo_control_out   <= #1 4'h0;
        // data and address outputs assignments to PCIW_FIFO - correction of 2 LSBits 
        pciw_fifo_addr_data_out <= #1 32'h0; 
        pciw_fifo_cbe_out       <= #1 4'h0;
    end
    else
    begin
        pciw_fifo_wenable_out                       <= #1 load_to_pciw_fifo_in ;
        pciw_fifo_control_out[`ADDR_CTRL_BIT]       <= #1 ~rdy_in ;
        pciw_fifo_control_out[`BURST_BIT]           <= #1 rdy_in ? ~frame_reg_in : 1'b0 ;
        // if '1' then next burst BE is not equat to current one => burst will be chopped into single transfers
        pciw_fifo_control_out[`DATA_ERROR_CTRL_BIT] <= #1 rdy_in && (next_be_in != be_in) && ~bckp_trdy_in; // valid comp. 
        pciw_fifo_control_out[`LAST_CTRL_BIT]       <= #1 rdy_in && (frame_reg_in || (bckp_trdy_in && ~bckp_stop_in));
        // data and address outputs assignments to PCIW_FIFO - correction of 2 LSBits 
        pciw_fifo_addr_data_out                     <= #1 rdy_in ? data_in : {norm_address[31:2], 
                                                                          norm_address[1] && io_memory_bus_command, 
                                                                          norm_address[0] && io_memory_bus_command} ; 
        pciw_fifo_cbe_out                           <= #1 rdy_in ? be_in : norm_bc ;
    end
end

`ifdef		HOST
	`ifdef	NO_CNF_IMAGE
			// data and address outputs assignments to PCI Target FSM
			assign	data_out = pcir_fifo_data ;
	`else
			// data and address outputs assignments to PCI Target FSM
			assign	data_out = sel_conf_fifo_in ? conf_data_in : pcir_fifo_data ;
	`endif
`else
			// data and address outputs assignments to PCI Target FSM
			assign	data_out = sel_conf_fifo_in ? conf_data_in : pcir_fifo_data ;
`endif

// data and address outputs assignments to read request sinchronization module
assign	req_out = req_in ;
	// this address is stored in delayed_sync module and is connected back as strd_addr_in 
assign	addr_out = norm_address[31:0] ; // correction of 2 LSBits is done in wb_master module, original address must be saved
assign	be_out = be_in ;
assign	we_out = 1'b0 ;
assign	bc_out = norm_bc ;
// 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)
assign	burst_ok_out = (norm_bc[3] && addr_burst_ok) || (norm_bc[2] && norm_prf_en && addr_burst_ok) ;
// data and address outputs assignments to Configuration space
`ifdef		HOST
	`ifdef	NO_CNF_IMAGE
			assign	conf_data_out	= 32'h0 ;
			assign	conf_addr_out	= 12'h0 ;
			assign	conf_be_out		= 4'b0 ;
			assign	conf_we_out		= 1'h0 ;
	`else
			assign	conf_data_out	= data_in ;
			assign	conf_addr_out	= strd_address[11:0] ;
			assign	conf_be_out		= be_in ;
			assign	conf_we_out		= load_to_conf_in ;
	`endif
`else
			assign	conf_data_out	= data_in ;
			assign	conf_addr_out	= strd_address[11:0] ;
			assign	conf_be_out		= be_in ;
			assign	conf_we_out		= load_to_conf_in ;
`endif
// NOT USED NOW, SONCE READ IS ASYNCHRONOUS
//assign	conf_re_out = fetch_conf_in ;
assign	conf_re_out = 1'b0 ;

endmodule