/******************************************************************************/
/* */
/* Copyright (c) 1999 Sun Microsystems, Inc. All rights reserved. */
/* */
/* The contents of this file are subject to the current version of the Sun */
/* Community Source License, microSPARCII ("the License"). You may not use */
/* this file except in compliance with the License. You may obtain a copy */
/* of the License by searching for "Sun Community Source License" on the */
/* World Wide Web at http://www.sun.com. See the License for the rights, */
/* obligations, and limitations governing use of the contents of this file. */
/* */
/* Sun Microsystems, Inc. has intellectual property rights relating to the */
/* technology embodied in these files. In particular, and without limitation, */
/* these intellectual property rights may include one or more U.S. patents, */
/* foreign patents, or pending applications. */
/* */
/* Sun, Sun Microsystems, the Sun logo, all Sun-based trademarks and logos, */
/* Solaris, Java and all Java-based trademarks and logos are trademarks or */
/* registered trademarks of Sun Microsystems, Inc. in the United States and */
/* other countries. microSPARC is a trademark or registered trademark of */
/* SPARC International, Inc. All SPARC trademarks are used under license and */
/* are trademarks or registered trademarks of SPARC International, Inc. in */
/* the United States and other countries. Products bearing SPARC trademarks */
/* are based upon an architecture developed by Sun Microsystems, Inc. */
/* */
/******************************************************************************/
/***************************************************************************
****************************************************************************
***
*** Program File: @(#)afxmaster.v
***
*** Description:
*** This is the afx master block for the Falcon pci bridge.
*** It works with the PCI slave block to form the DMA path
*** between PCI devices and host memory.
***
****************************************************************************
****************************************************************************/
`timescale 1ns/1ns
module afxmaster
(
// add for 2.0 stale data problem
tar_trdyout,
pcis_big_endian,
// PCI SLAVE SIGNALS
tar_rcv1_fifo_read,
tar_rcv_fifo_flush,
tar_rcv1_dataout,
tar_rcv1_fifo_be_out,
tar_rcv1_fifo_next_be_out,
tar_rcv1_fifo_empty,
tar_rcv1_fifo_full,
tar_rcv2_fifo_full,
tar_rcv1_half_full,
tar_rcv2_half_full,
tar_rcv1_almost_full,
tar_rcv2_almost_full,
tar_rcv2_fifo_read,
tar_rcv2_dataout,
tar_rcv2_fifo_be_out,
tar_rcv2_fifo_next_be_out,
tar_rcv2_fifo_empty,
rcv_fifo_inpempty,
tar_xmit1_data_in,
tar_xmit1_fifo_write,
tar_xmit1_fifo_write_ptr,
tar_xmt_fifo_flush,
tar_xmt_fifo_empty,
tar_xmt_fifo_outempty,
tar_xmit1_fifo_full,
tar_xmit2_data_in,
tar_xmit2_fifo_write,
tar_xmit2_fifo_write_ptr,
tar_xmit2_fifo_full,
txmt_stop_fifowr,
cdec_address,
cdec_curCmd,
force_pci_retry,
retry_condition,
tar_valid_cmd,
tar_valid_cmd_early,
afxm_idle_cyc,
afxm_dma_read,
afxm_read_alert,
pclk,
pci_clk_sync,
pci_clk_sync_,
// AFX SIGNALS
am_cstb_l,
am_read,
cas_cyc,
valid_l,
am_gnt_l,
mm_oddpar,
gclk,
gclk_sync,
gclk_sync_,
about,
aboe,
dbin,
dbout,
dboe2_in,
am_wm,
mparin,
dp_perr,
mparout,
reset_l,
// MISC SIGNALS
req_quiescence,
ack_quiescence,
req_q_retry,
afx_m_idle,
discard_timer,
// IOTLB signals
standby_dsbl_tlb, // iotlb power down mode input
iotlb_cd_in_reg, // iotlb cam input data register
iotlb_rd_in_reg, // iotlb ram input data register
iotlb_cd_out_reg, // iotlb cam output data register
iotlb_rd_out_reg, // iotlb ram output data register
iotlb_cntl_reg, // iotlb control input register
iotlb_cntl_wrt, // iotlb control write pulse
dma_err, // iotlb miss or parity error
dma_err_address, // iotlb miss or parity error address
iotlb_enable // iotlb bypass or enable
);
// add for stale data flush fix for 2.0
input tar_trdyout
;
input pcis_big_endian
;
// PCI SLAVE SIGNALS
output tar_rcv1_fifo_read
;
output tar_rcv_fifo_flush
;
input [31:0] tar_rcv1_dataout
;
input [3:0] tar_rcv1_fifo_be_out
;
input [3:0] tar_rcv1_fifo_next_be_out
;
input tar_rcv1_fifo_empty
;
input tar_rcv1_fifo_full
;
input tar_rcv1_half_full
;
input tar_rcv1_almost_full
;
output tar_rcv2_fifo_read
;
input [31:0] tar_rcv2_dataout
;
input [3:0] tar_rcv2_fifo_be_out
;
input [3:0] tar_rcv2_fifo_next_be_out
;
input tar_rcv2_fifo_empty
;
input tar_rcv2_fifo_full
;
input tar_rcv2_half_full
;
input tar_rcv2_almost_full
;
input rcv_fifo_inpempty
;
input [2:0] tar_xmit1_fifo_write_ptr
;
input [2:0] tar_xmit2_fifo_write_ptr
;
output [31:0] tar_xmit1_data_in
;
output tar_xmit1_fifo_write
;
output tar_xmt_fifo_flush
;
input tar_xmit1_fifo_full
;
input tar_xmt_fifo_empty
;
input tar_xmt_fifo_outempty
;
output [31:0] tar_xmit2_data_in
;
output tar_xmit2_fifo_write
;
input tar_xmit2_fifo_full
;
input txmt_stop_fifowr
;
input [31:0] cdec_address
;
input [3:0] cdec_curCmd
;
output force_pci_retry
;
input retry_condition
;
input tar_valid_cmd
;
input tar_valid_cmd_early
;
output afxm_idle_cyc
;
output afxm_dma_read
;
output afxm_read_alert
;
input pclk
;
input pci_clk_sync
; // for sync ckts
input pci_clk_sync_
; // for sync ckts
// AFX SIGNALS
output am_cstb_l
; // transfer request to afx master
output am_read
; // r/w indicator on Falcon transfers
input valid_l
; // read/write strobe for falcon afx master
input cas_cyc
; // low addr for falcon afx master
input am_gnt_l
; // afx grant for falcon
input mm_oddpar
; // from mmu PCR: odd/even parity
input gclk
; // afx clock @ 1/3 cpu clock
input gclk_sync
; // for sync ckts
input gclk_sync_
; // for sync ckts
output [14:0] about
; // muxed addr/byte mask row/col address
output aboe
; // address bus output enable, 4 copies
input [63:0] dbin
; // input afx data bus
output [63:0] dbout
; // afx DMA write data out
output dboe2_in
; // afx DMA write data bus enable (to be or'ed and
// flopped with afx_slave dboe)
output [1:0] am_wm
; // afx word mask
input [1:0] mparin
; // input afx data parity
input [1:0] dp_perr
; // parity error from memif
output [1:0] mparout
; // afx write data parity
input reset_l
; // system reset
input req_quiescence
; // cpu request to flush write buffers
output ack_quiescence
; // Falcon acknwledge to cpu that flush
// is done and Falcon afxm is quiescent
output req_q_retry
; // quiescence req to retry
// pci slave
output afx_m_idle
; // afx master idle AND fifo's are empty too.
input [14:0] discard_timer
; // discard timer timeout max (from config reg @0x68)
// IOTLB interface
output [31:0] iotlb_cd_out_reg
;
output [31:0] iotlb_rd_out_reg
;
output dma_err
;
output [31:0] dma_err_address
;
input [31:0] iotlb_cd_in_reg
;
input [31:0] iotlb_rd_in_reg
;
input [7:0] iotlb_cntl_reg
;
input iotlb_cntl_wrt
;
input iotlb_enable
;
input standby_dsbl_tlb
;
parameter MAX_XFER = 4'h7; //max afx burst xfer memif allows
wire [3:0] dma_bm
;
reg dma_burst
;
wire idle_cyc
;
wire idle_cyc_p
;
wire idle_cyc_p2
;
wire afx_m_idle;
wire req_cyc
;
wire radr_cyc
, radr_cyc1
;
reg radr_cyc2
; //2.0 addition
wire cadr_cyc
, cadr_cyc1
;
wire data_cyc
,data_cyc1
;
wire hold_cyc
,hold_cyc1
;
wire error
;
wire aboe; //
wire aboe5
; //5th copy, used internally
wire dboe2_in; //to be or'ed an flopped with afx_slave dboe
reg dboe_ff
; //internal copy
wire tar_valid_cmd ;
wire tar_valid_cmd_early ;
wire [ 3:0] tar_rcv1_fifo_be_out ;
wire [ 3:0] tar_rcv2_fifo_be_out ;
wire save_addr
;
wire discard_timeout
;
reg discard_timeout1
;
wire discard_ok_g
, discard_ok
;
wire am_cstb_l;
wire am_gnt_l;
wire [3:0] cdec_curCmd ;
// enabled mem read and write for IO commands below
wire pci_mem_rd_p
= (cdec_curCmd == 4'h6) |
(cdec_curCmd == 4'hc) |
(cdec_curCmd == 4'he) |
(cdec_curCmd == 4'h2); //pci_io_rd
//create gclk-synced version of pci_mem_rd
wire pci_mem_rd_g
;
sync s24 (.out(pci_mem_rd_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(pci_mem_rd_p));
wire pci_mem_wrt_p
= (cdec_curCmd == 4'h7) |
(cdec_curCmd == 4'hf) |
(cdec_curCmd == 4'h3); //pci_io_wrt
//create gclk-synced version of pci_mem_wrt
wire pci_mem_wrt_g
;
sync s25 (.out(pci_mem_wrt_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(pci_mem_wrt_p));
reg tar_valid_cmd1
;
reg pci_mem_wrt_p1
;
always @(posedge pclk) begin
tar_valid_cmd1 <= #1 tar_valid_cmd;
pci_mem_wrt_p1 <= #1 pci_mem_wrt_p ;
end
wire tar_valid_cmd_p
= tar_valid_cmd | tar_valid_cmd1;
//create gclk-synced version of tar_valid_cmd
wire tar_valid_cmd_g
;
sync s1 (.out(tar_valid_cmd_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(tar_valid_cmd_p));
wire cmd_start_p
= tar_valid_cmd_p & (pci_mem_rd_p | pci_mem_wrt_p) ;
wire cmd_start_g
= tar_valid_cmd_g & (pci_mem_rd_g | pci_mem_wrt_g) ;
reg cmd_start_g1
;
reg pci_mem_wrt_g1
;
always @(posedge gclk) begin
cmd_start_g1 <= #1 cmd_start_g;
pci_mem_wrt_g1 <= #1 pci_mem_wrt_g ;
end
wire tar_rcv1_fifo_empty;
wire tar_rcv2_fifo_empty;
wire rcv_fifo_empty_g
= (tar_rcv1_fifo_empty & tar_rcv2_fifo_empty) ||
tar_rcv_fifo_flush;
//wire trcv_full = tar_rcv1_fifo_full | tar_rcv2_fifo_full;
//wire trcv_half_full = tar_rcv1_half_full & tar_rcv2_half_full;
//wire trcv_qtr_full = ~(tar_rcv1_fifo_empty | tar_rcv2_fifo_empty);
wire trcv_qtr_full
= ~(tar_rcv1_fifo_empty | tar_rcv2_fifo_empty);
wire oe_off
;
wire start_xfer_g
;
wire back2idle
= rcv_fifo_empty_g & idle_cyc;
wire am_gnt_l1
;
reg [31:0] start_addr
;
reg [31:0] dma_addr
;
wire delayed_read
;
reg read_alert
;
wire dma_read
;
//2.0: added delayed_read_g for write_alert (used to use
// delayed_read
wire delayed_read_g
;
sync s2 (.out(delayed_read_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(delayed_read));
wire write_alert
= ~read_alert & ~delayed_read_g &
~rcv_fifo_empty_g & ~ack_quiescence;
wire write_alert_p
;
sync s22 (.out(write_alert_p),.in_clk(pci_clk_sync),.out_clk(pci_clk_sync_),.in(write_alert));
wire [31:0] cdec_address ;
reg [31:0] retried_addr
;
wire retry_addr_match
;
reg unaligned
;
reg [2:0] xfer_count
;
reg [63:0] afx_rdata
;
reg [1:0] afx_mpar
;
wire read_start_p
;
wire txmt_stop_fifo_wr0
;
wire txmt_stop_fifo_wr
;
reg rmw
;
wire pend_abort_write
;
wire delayed_abort_write
;
wire rmw_write
;
//2.0: fix to pn138: add ~delayed_read term
//wire afxm_idle_cyc = idle_cyc_p;
wire afxm_idle_cyc = idle_cyc_p & ~delayed_read;
//2.0: change idle_cyc_p to idle_cyc
//wire dma_read_to_pcis = (dma_read & ~rmw) | (pend_abort_write & idle_cyc_p);
wire dma_read_to_pcis
= (dma_read & ~rmw) | (pend_abort_write & idle_cyc);
wire afxm_dma_read;
sync s13 (.out(afxm_dma_read),.in_clk(pci_clk_sync),.out_clk(pci_clk_sync_),.in(dma_read_to_pcis));
sync s14 (.out(idle_cyc_p),.in_clk(pci_clk_sync),.out_clk(pci_clk_sync_),.in(idle_cyc));
sync s17 (.out(idle_cyc_p2),.in_clk(pci_clk_sync_),.out_clk(pci_clk_sync),.in(idle_cyc));
reg tar_rcv_fifo_flush;
wire rcv_fifo_empty_p
= rcv_fifo_inpempty | tar_rcv_fifo_flush;
wire force_pci_retry;
reg tar_xmt_fifo_flush;
wire tar_xmt_fifo_empty_g
= tar_xmt_fifo_empty;
wire tar_xmt_fifo_empty_p
= tar_xmt_fifo_outempty | tar_xmt_fifo_flush;
assign afx_m_idle = idle_cyc_p2 & tar_xmt_fifo_empty_p & rcv_fifo_empty_p ;
wire req_q_rd
; //req_q_rd qualified for delayed read case
//wire req_q_retry = (req_quiescence | ack_quiescence) & ~read_alert |
// req_q_rd & read_alert;
wire req_q_retry = req_quiescence | ack_quiescence ;
wire rmw_next
;
wire read_alert_p
;
sync s31 (.out(read_alert_p),.in_clk(pci_clk_sync_),.out_clk(pci_clk_sync),.in(read_alert));
//2.0: new output to pci_slave
wire afxm_read_alert = read_alert_p;
//read_pack_done makes the retry_sm wait till at least 1 read word data
//has been written packed) into xmit fifos before accepting the
//returning read master.
//2.0: redefined read_pack_done
//wire read_pack_done = ((tar_xmit1_fifo_write_ptr > 3'h0) & (tar_xmit2_fifo_write_ptr > 3'h0)) |
wire read_pack_done
= ~tar_xmt_fifo_empty_p;
reg cmd_start_p1
;
wire flush_stale_read
;
retry_sm retry_sm1(force_pci_retry, save_addr, discard_timeout,
pclk, reset_l, flush_stale_read, cmd_start_p, cmd_start_p1,
pci_mem_rd_p, pci_mem_wrt_p,
delayed_read, idle_cyc_p, rcv_fifo_empty_p,
tar_xmt_fifo_empty_p, retry_addr_match, read_pack_done,
ack_quiescence, discard_timer, discard_ok);
always @(posedge pclk) begin
discard_timeout1 <= #1 discard_timeout;
end
assign discard_ok_g = ~tar_xmt_fifo_empty_g & ~read_alert &
~data_cyc & ~hold_cyc;
sync s501 (.out(discard_ok),.in_clk(pci_clk_sync_),.out_clk(pci_clk_sync),.in(discard_ok_g));
always @(posedge pclk) begin
if (~reset_l)
retried_addr <= #1 32'b0;
else if (save_addr)
retried_addr <= #1 cdec_address;
end
// change this to be only the same number of bits as the
// the flush compare below to make a gate fix possible.
assign retry_addr_match = (retried_addr == cdec_address);
//assign retry_addr_match = (retried_addr[31:12] == cdec_address[31:12]);
wire retry_condition_p
= retry_condition;
wire force_pci_retry_g
;
sync s15 (.out(force_pci_retry_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(force_pci_retry));
wire retry_condition_g
;
sync s29 (.out(retry_condition_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(retry_condition_p));
wire save_start_addr
= cmd_start_p & ~cmd_start_p1 &
//((pci_mem_wrt_p & ~retry_condition_p ) |
((pci_mem_wrt_p) |
//2.0: change read_alert to read_alert_p (1.0 bug? )
//(pci_mem_rd_p & rcv_fifo_empty_p & ~read_alert));
(pci_mem_rd_p & rcv_fifo_empty_p & ~read_alert_p));
start_xfer_sm start_xfer_sm1 (start_xfer_g,
gclk, reset_l, cmd_start_g, cmd_start_g1,
pci_mem_wrt_g1, pci_mem_rd_g, retry_condition_g,
rcv_fifo_empty_g, tar_xmt_fifo_empty_g, idle_cyc,
force_pci_retry_g);
//2.0: substituted tar_xmt_fifo_empty_g with am_gnt_l
//rcv_fifo_empty_g, am_gnt_l, idle_cyc, force_pci_retry_g);
quiescent_sm q_sm(ack_quiescence, req_q_rd,
req_quiescence, pclk, reset_l ,tar_valid_cmd_early,
read_alert, rcv_fifo_empty_p , tar_xmt_fifo_empty_p ,
//2.0: replace idle_cyc_p with afxm_idle_cyc (see
// pn138)
//delayed_read, retry_addr_match, idle_cyc_p);
delayed_read, retry_addr_match, afxm_idle_cyc);
reg nonaligned_start_addr_p
;
always @(posedge pclk) begin
if (~reset_l) begin
start_addr <= #1 32'b0;
nonaligned_start_addr_p <= #1 1'b0;
end
else if (save_start_addr) begin
start_addr <= #1 {cdec_address[31:3],3'b0} ;
nonaligned_start_addr_p <= #1 cdec_address[2];
end
end
wire nonaligned_start_addr
;
sync s26 (.out(nonaligned_start_addr),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(nonaligned_start_addr_p));
reg start_xfer_g1
;
always @(posedge pclk) begin
cmd_start_p1 <= #1 cmd_start_p;
end
//2.0 add read_pack_done
start_sm start_sm1 (read_start_p, delayed_read,
pclk, reset_l, cmd_start_p, cmd_start_p1,
pci_mem_rd_p, rcv_fifo_empty_p,
tar_xmt_fifo_empty_p, force_pci_retry, idle_cyc_p,
ack_quiescence);
//ack_quiescence, read_pack_done);
wire read_start
;
sync s28 (.out(read_start),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(read_start_p));
always @(posedge gclk) begin
start_xfer_g1 <= #1 start_xfer_g;
end
wire preempted
;
reg am_read;
always @(posedge gclk) begin
am_read <= #1
~((rmw & ~rmw_write & ((cadr_cyc&cas_cyc) | data_cyc | hold_cyc)) ||
(write_alert & rmw & rmw_write & ~rmw_next) ||
(write_alert & ~rmw_next & ~rmw) ||
(write_alert & rmw_next & ~rmw & ~am_cstb_l) ||
(~write_alert & ~read_alert & ~dma_read)
);
end
wire afxm_idle
= (~write_alert & ~read_alert) | error;
wire [31:0] next_addr
;
wire [2:0] xfercount
;
wire dma_addr12
= dma_addr[12];
wire nxt_addr12
= next_addr[12];
//2.0: replace cross_page flop with wire (1.0/1.1 bug! see pn137)
/*
reg cross_page;
always @(posedge gclk) begin
if (~(data_cyc & valid_l))
cross_page <= #1 ~(nxt_addr12 == dma_addr12) & ~am_gnt_l;
end
*/
wire cross_page
= (nxt_addr12 != dma_addr12) & ~am_gnt_l;
wire dma_burst_in
= ~afxm_idle & ~cross_page & ~rmw_write & (xfer_count < MAX_XFER);
always @(posedge gclk) begin
if (idle_cyc | radr_cyc | cadr_cyc | hold_cyc)
dma_burst <= #1 dma_burst_in;
end
wire txmt_stop_fifo_wr_g
;
wire abort_write
;
reg valid_l1
;
wire write_aborted
; //used to sync up on next burst
wire incr_ok
= aboe5 & ~am_gnt_l & ~(rmw & ~rmw_write) & ~pend_abort_write &
~abort_write & ~write_aborted;
wire tar_xmit_fifo_full
= tar_xmit1_fifo_full | tar_xmit2_fifo_full;
reg inhibit_xmit_write
;
always @(posedge gclk ) begin
// valid_l1 used to reduce valid_l loading
//2.0: adjust since initial rcv_fifo read strobe timing changed
//if (~reset_l | ((write_alert & radr_cyc) | (read_alert & ~valid_l1)))
//2.0: add ~inhibit_xmit_write (see PN134)
if (~reset_l | ((write_alert & radr_cyc1 & ~radr_cyc2) | (read_alert & ~valid_l1 & ~inhibit_xmit_write)))
//turn off unaligned flag after first unaligned data has been
//read out of tar_rcv2 on writes or written into tar_xmit2 on reads.
//or initialize on system reset
unaligned <= #1 1'b0;
//initialize unaligned flag based on starting address alignment
else if (start_xfer_g | start_xfer_g1)
unaligned <= #1 nonaligned_start_addr;
//dma_addr
if (~reset_l)
dma_addr <= #1 32'b0;
//load starting address at start
else if (start_xfer_g)
dma_addr <= #1 start_addr;
//increment address
else if (incr_ok & data_cyc & ~data_cyc1)
dma_addr[31:0] <= #1 next_addr[31:0];
//data transfer count
//if (~reset_l | start_xfer_g)
if (~reset_l | am_gnt_l)
xfer_count <= #1 3'b0;
//increment data transfer count
else if (~valid_l)
xfer_count <= #1 xfercount;
//reset read_alert
if (~reset_l)
read_alert <= #1 1'b0;
else
//initialize read_alert flag at beginning of read transaction
if (~read_alert)
read_alert <= #1 read_start;
else
//turn off read_alert flag after 3rd valid_l so afxm stops
//after 4th xfer--unless pci_slave asserts txmt_stop_fifo_wr
//to indicate initiator has terminated the read
//2.0: corollary fix to pn137
//if (read_alert & ((~valid_l & (xfer_count==(MAX_XFER-1) | cross_page)) |
if (read_alert & ((~valid_l & (xfer_count==(MAX_XFER-1)) | cross_page) |
//2.0: add read_start term (necessary?)
(txmt_stop_fifo_wr_g & ~read_start) |
ack_quiescence))
read_alert <= #1 1'b0;
end
assign next_addr[31:3] = dma_addr[31:3] + 1'b1;
assign next_addr[2:0] = 3'b000;
assign xfercount = xfer_count + 1'b1;
always @(posedge gclk) begin
valid_l1 <= #1 valid_l;
end
/* DMA READ STUFF */
//flushing read buffers
assign txmt_stop_fifo_wr0 = txmt_stop_fifowr;
reg txmt_stop_fifo_wr1
;
always @(posedge pclk) begin
txmt_stop_fifo_wr1 <= #1 txmt_stop_fifo_wr0;
end
assign txmt_stop_fifo_wr = txmt_stop_fifo_wr0 | txmt_stop_fifo_wr1;
//txmt_stop_fifo_wr_g needed?
sync s16 (.out(txmt_stop_fifo_wr_g),.in_clk(gclk_sync),.out_clk(gclk_sync_),.in(txmt_stop_fifo_wr));
//flushing stale read data (case where read data is sitting in
//read buffers and a write to same location comes in before
//read completes).
//assign flush_stale_read = save_start_addr & pci_mem_wrt_p & ~tar_xmt_fifo_empty_p &
assign flush_stale_read = ~tar_trdyout & pci_mem_wrt_p & ~tar_xmt_fifo_empty_p &
//2.0: compare within 4K page to make sure
// entire read fifo is compared against
// starting write address.
//( {cdec_address[31:3],3'b0} == retried_addr);
(cdec_address[31:12] == retried_addr[31:12]);
// note tar_xmt_fifo_flush is synced with pclk
always @(posedge pclk) begin
tar_xmt_fifo_flush <= #1 read_start_p | txmt_stop_fifo_wr |
flush_stale_read | discard_timeout |
ack_quiescence;
end
reg unaligned1
;
always @(posedge gclk) begin
unaligned1 <= #1 unaligned;
end
//2.0: introduce inhibit on tar_xmit_fifo_writes to keep xmit fifo
// from being written again after flush.
always @(posedge gclk) begin
if (txmt_stop_fifo_wr_g)
inhibit_xmit_write <= #1 1'b1;
else if (xfer_count == 3'h0)
inhibit_xmit_write <= #1 1'b0;
end
//write enables for pci read buffers
reg tar_xmit1_fifo_write, tar_xmit2_fifo_write;
always @(posedge gclk) begin
tar_xmit1_fifo_write <= #1 dma_read & ~rmw & ~valid_l &
~tar_xmit1_fifo_full & ~unaligned & ~inhibit_xmit_write;
tar_xmit2_fifo_write <= #1 dma_read & ~rmw & ~valid_l &
~tar_xmit2_fifo_full & ~inhibit_xmit_write;
end
//read enables for pci read buffers
//latching in read data from afx db
always @(posedge gclk) begin
if (~reset_l ) begin
afx_rdata <= #1 64'b0;
afx_mpar <= #1 2'b0;
end
else if (aboe5 & ~dboe_ff & dma_read & data_cyc) begin
afx_rdata <= #1 dbin;
afx_mpar <= #1 mparin;
end
end
wire [1:0] memif_perr
= ~am_gnt_l & dma_read ? dp_perr[1:0] : 2'b0;
wire afx_perr
= memif_perr[1] | memif_perr[0];
wire [1:0] afx_rdata_par
= {^(afx_rdata[63:32]),^(afx_rdata[31:0])};
//convert read data from big to little endian
wire [31:0] tar_xmit1_data_in = {afx_rdata[39:32],afx_rdata[47:40],
afx_rdata[55:48],afx_rdata[63:56]};
wire [31:0] tar_xmit2_data_in = {afx_rdata[7:0],afx_rdata[15:8],
afx_rdata[23:16],afx_rdata[31:24]};
reg trcv1_val
, trcv2_val
;
wire [3:0] rmw_data2_mask
= trcv2_val ? tar_rcv2_fifo_be_out[3:0] : 4'b1111;
wire [3:0] rmw_data1_mask
= trcv1_val ? tar_rcv1_fifo_be_out[3:0] : 4'b1111;
//rmw read data masking
wire [63:0] rmw_rdata
;
assign rmw_rdata[63:32] = {tar_xmit2_data_in[31:24] & {8{rmw_data2_mask[3]}},
tar_xmit2_data_in[23:16] & {8{rmw_data2_mask[2]}},
tar_xmit2_data_in[15:8] & {8{rmw_data2_mask[1]}},
tar_xmit2_data_in[7:0] & {8{rmw_data2_mask[0]}}};
assign rmw_rdata[31:0] = {tar_xmit1_data_in[31:24] & {8{rmw_data1_mask[3]}},
tar_xmit1_data_in[23:16] & {8{rmw_data1_mask[2]}},
tar_xmit1_data_in[15:8] & {8{rmw_data1_mask[1]}},
tar_xmit1_data_in[7:0] & {8{rmw_data1_mask[0]}}};
/* DMA WRITE STUFF */
reg am_gnt_ff
;
always @(posedge gclk ) begin
am_gnt_ff <= #1 am_gnt_l;
end
assign am_gnt_l1 = am_gnt_ff;
reg tar_rcv1_fifo_empty1
;
reg tar_rcv2_fifo_empty1
;
reg rcv_fifo_empty_g1
;
always @(posedge gclk ) begin
tar_rcv1_fifo_empty1 <= #1 tar_rcv1_fifo_empty;
tar_rcv2_fifo_empty1 <= #1 tar_rcv2_fifo_empty;
rcv_fifo_empty_g1 <= #1 rcv_fifo_empty_g;
end
//read enables for pci write buffers
reg tar_rcv1_fifo_read;
reg tar_rcv2_fifo_read;
//2.0: change first read strobe from req_cyc to radr_cyc1
always @(posedge gclk) begin
radr_cyc2 <= #1 radr_cyc1;
end
//wire read1 = req_cyc & ~preempted & (~am_read|rmw_next);
wire read1
= radr_cyc & ~radr_cyc1 & ~preempted & (~am_read|rmw_next);
wire read2
= cadr_cyc & cas_cyc & ~dma_read & ~rmw &
~cross_page & ~rmw_next & dboe_ff & ~abort_write;
wire read3
= hold_cyc & ~dma_read & ~am_gnt_l & ~rmw & dma_burst &
~cross_page & ~rmw_next & dboe_ff & ~abort_write &
(xfer_count < MAX_XFER);
always @(posedge gclk ) begin
tar_rcv1_fifo_read <= #1 (read1 & ~tar_rcv1_fifo_empty & ~unaligned & ~abort_write & ~write_aborted) |
(read2 & ~tar_rcv1_fifo_empty & ~write_aborted) |
(read3 & ~tar_rcv1_fifo_empty & ~write_aborted) ;
tar_rcv2_fifo_read <= #1 (read1 & ~tar_rcv2_fifo_empty) |
(read2 & ~tar_rcv2_fifo_empty) |
(read3 & ~tar_rcv2_fifo_empty) ;
end
/*
wire tar_rcv1_fifo_read;
wire tar_rcv2_fifo_read;
wire tar_rcv1_fifo_read = (~tar_rcv1_fifo_empty & cadr_cyc & ~cadr_cyc1 &
~preempted & ~unaligned & ~abort_write & ~write_aborted &
(~dma_read|rmw_next)) ||
(data_cyc & ~data_cyc1 & dma_burst & ~dma_read & ~rmw
& ~rmw_next & dboe_ff & ~tar_rcv1_fifo_empty & ~abort_write & ~write_aborted);
wire tar_rcv2_fifo_read = (~tar_rcv2_fifo_empty & cadr_cyc & ~cadr_cyc1 & ~abort_write &
~preempted & (~dma_read|rmw_next)) ||
(data_cyc & ~data_cyc1 & dma_burst & ~dma_read & ~rmw
& ~rmw_next & dboe_ff & ~tar_rcv2_fifo_empty & ~abort_write);
*/
wire rcv_fifo_read
= tar_rcv1_fifo_read | tar_rcv2_fifo_read;
//Detect case where last write data is single word but dw-aligned
wire last_single
= (radr_cyc | data_cyc) &
tar_rcv1_fifo_read & ~tar_rcv2_fifo_read;
//muxing of dma write data
wire [31:0] tar_rcv1_dataout, tar_rcv2_dataout;
wire [63:0] rmw_wdata
;
wire [63:0] rmw_dataout
;
always @(posedge gclk) begin
if (~reset_l | idle_cyc | (req_cyc & ~preempted)) begin
trcv1_val <= #1 1'b0;
trcv2_val <= #1 1'b0;
end
//2.0: adjust since initial rcv_fifo read strobe timing changed:
//else if ((radr_cyc & ~radr_cyc1) | (data_cyc & ~data_cyc1 & ~rmw)) begin
else if ((radr_cyc1 & ~radr_cyc2) | (data_cyc & ~data_cyc1 & ~rmw)) begin
trcv1_val <= #1 tar_rcv1_fifo_read;
trcv2_val <= #1 tar_rcv2_fifo_read;
end
end
wire trcv_val
= trcv1_val | trcv2_val;
wire [63:0] dma_data
;
wire [63:0] trcv_datamux
;
assign trcv_datamux[63:32] = trcv2_val ? tar_rcv2_dataout : 32'b0;
assign trcv_datamux[31:0] = trcv1_val ? tar_rcv1_dataout : 32'b0;
assign dma_data = rmw ? rmw_dataout : trcv_datamux;
//function to convert pci be's (8 bits) to 2-bit afx word mask
//detect if next xfer is rmw, based on next byte enables
wire [1:0] word_mask_next
;
wire [3:0] trcv2_next_be_out
= tar_rcv2_fifo_next_be_out;
wire [3:0] trcv1_next_be_out
= tar_rcv1_fifo_next_be_out;
assign word_mask_next = ~tar_rcv2_fifo_empty & ~tar_rcv1_fifo_empty ?
wm_encode({trcv2_next_be_out,trcv1_next_be_out}) :
~tar_rcv2_fifo_empty & tar_rcv1_fifo_empty ?
wm_encode({trcv2_next_be_out,4'b1111}) :
tar_rcv2_fifo_empty & ~tar_rcv1_fifo_empty ?
wm_encode({4'b1111,trcv1_next_be_out}) :
2'b11;
assign rmw_next = (word_mask_next==2'b0);
always @(posedge gclk) begin
if (~reset_l)
rmw <= #1 1'b0;
else if (idle_cyc |
(hold_cyc & rmw_write) |
(data_cyc & am_gnt_l & (dma_burst|trcv_val))) //preempted
rmw <= #1 rmw_next;
else
rmw <= #1 rmw;
end
wire trcv2_only
= ~tar_rcv2_fifo_empty;
//2.0: add new wire for abort_write_sm; signals when no valid
// write data has been read out of rcv fifos due to temp
// empty condition; causes a quick abort of the afx write cycle.
wire no_rcv_read
= ((radr_cyc1 & ~radr_cyc2) | (data_cyc & ~data_cyc1 & ~rmw)) &
~tar_rcv1_fifo_read & ~tar_rcv2_fifo_read &
~dma_read;
reg no_rcv_read_ff
;
always @(posedge gclk) begin
if (data_cyc & ~data_cyc1)
no_rcv_read_ff <= #1 no_rcv_read;
end
wire new_cmd_start
= cmd_start_g & ~cmd_start_g1;
abort_write_sm aw_sm (pend_abort_write, abort_write, write_aborted,
delayed_abort_write, gclk, reset_l,
last_single, no_rcv_read, valid_l, trcv2_only, data_cyc,
cas_cyc, radr_cyc, cadr_cyc, hold_cyc, idle_cyc,
req_cyc, tar_rcv2_fifo_read, new_cmd_start);
reg [1:0] word_mask
;
wire [1:0] word_maskin1
= tar_rcv2_fifo_read & tar_rcv1_fifo_read ?
wm_encode({tar_rcv2_fifo_next_be_out,tar_rcv1_fifo_next_be_out}) :
tar_rcv2_fifo_read & ~tar_rcv1_fifo_read ?
wm_encode({tar_rcv2_fifo_next_be_out,4'b1111}) :
~tar_rcv2_fifo_read & tar_rcv1_fifo_read ?
wm_encode({4'b1111,tar_rcv1_fifo_next_be_out}) :
word_mask;
wire [1:0] word_maskin2
= trcv2_val & trcv1_val ?
wm_encode({tar_rcv2_fifo_be_out,tar_rcv1_fifo_be_out}) :
trcv2_val & ~trcv1_val ?
wm_encode({tar_rcv2_fifo_be_out,4'b1111}) :
~trcv2_val & trcv1_val ?
wm_encode({4'b1111,tar_rcv1_fifo_be_out}) :
//2.0: change for quick_abort condition
~trcv2_val & ~trcv1_val & ~delayed_abort_write & no_rcv_read_ff ?
//word_mask;
2'b0 :
word_mask;
always @(posedge gclk) begin
if (~reset_l | dma_read | rmw)
word_mask <= #1 2'b11;
//2.0: adjust since init rcv_fifo read strobe changed timing
//else if (radr_cyc & ~radr_cyc1) begin
else if (radr_cyc1 & ~radr_cyc2) begin
word_mask <= #1 word_maskin1;
end
else if (hold_cyc) begin
word_mask <= #1 word_maskin2;
end
end
wire [1:0] am_wm = word_mask[1:0];
//rmw write data masking
assign rmw_wdata[63:32] = {trcv_datamux[63:56] & ~{8{rmw_data2_mask[3]}},
trcv_datamux[55:48] & ~{8{rmw_data2_mask[2]}},
trcv_datamux[47:40] & ~{8{rmw_data2_mask[1]}},
trcv_datamux[39:32] & ~{8{rmw_data2_mask[0]}}};
assign rmw_wdata[31:0] = {trcv_datamux[31:24] & ~{8{rmw_data1_mask[3]}},
trcv_datamux[23:16] & ~{8{rmw_data1_mask[2]}},
trcv_datamux[15:8] & ~{8{rmw_data1_mask[1]}},
trcv_datamux[7:0] & ~{8{rmw_data1_mask[0]}}};
//merge masked rmw_rdata and rmw_wdata
assign rmw_dataout = rmw_rdata | rmw_wdata;
//flushing write buffers
// note tar_rcv_fifo_flush is synced with pclk
always @(posedge pclk) begin
//tar_rcv_fifo_flush <= #1 cmd_start_p & ~cmd_start_p1 &
tar_rcv_fifo_flush <= #1 tar_valid_cmd_early & ~tar_valid_cmd &
pci_mem_wrt_p;
end
//
// adding iotlb between dma_addr register output, and about_ff register
//
reg [31:0] iotlb_rd_out_reg;
reg [31:0] iotlb_cd_out_reg;
reg iotlb_cntl_wrt_d1
;
reg iotlb_cntl_wrt_d2
;
reg iotlb_cntl_wrt_d3
;
wire iotlb_rdwrt
= (iotlb_cntl_wrt_d1 | iotlb_cntl_wrt_d2 | iotlb_cntl_wrt_d3 );
wire xlate_start
= ((idle_cyc | req_cyc | radr_cyc) & (start_xfer_g | start_xfer_g1));
wire xlate_incr
= incr_ok & (data_cyc & ~data_cyc1);
wire [41:0] iotlb_cd_in
;
wire [41:0] iotlb_cd_out
;
wire iotlb_valid_in
= iotlb_cd_in_reg[3];
wire iotlb_lvl3_in
= iotlb_cd_in_reg[0];
wire iotlb_lvl2_in
= iotlb_cd_in_reg[1];
wire iotlb_lvl1_in
= iotlb_cd_in_reg[2];
wire [27:0] iotlb_rd_in
= {iotlb_rd_in_reg[27:3], iotlb_lvl1_in, iotlb_lvl2_in, iotlb_lvl3_in};
wire [27:0] iotlb_rd_out
;
wire [3:0] iotlb_addr
= iotlb_cntl_reg[3:0];
wire tlb_we
= iotlb_cntl_reg[7];
wire tlb_flush
= iotlb_cntl_reg[6];
wire tlb_asel
= iotlb_cntl_reg[5];
wire iotlb_cr
= (iotlb_cntl_wrt_d1 & ~tlb_flush & ~tlb_we & tlb_asel);
wire iotlb_we
= (iotlb_cntl_wrt_d2 & ~tlb_flush & tlb_we & tlb_asel);
wire iotlb_flush
= (iotlb_cntl_wrt_d1 & tlb_flush & ~tlb_we & ~tlb_asel);
wire iotlb_asel
= (iotlb_cntl_wrt_d1 & ~tlb_flush & ~tlb_we & tlb_asel)
| (iotlb_cntl_wrt_d2 & ~tlb_flush & ~tlb_we & tlb_asel)
| (iotlb_cntl_wrt_d2 & ~tlb_flush & tlb_we & tlb_asel);
wire iotlb_miss
;
// wire iotlb_valid = iotlb_cd_out[41];
// wire iotlb_lvl3 = iotlb_cd_out[24];
// wire iotlb_lvl2 = iotlb_cd_out[31];
// wire iotlb_lvl1 = iotlb_cd_out[40];
// iotlb_cd_in_reg[31:12] == virtual address (index1,index2,index3)
// iotlb_cd_in_reg[3] == valid input bit
// iotlb_cd_in_reg[2:0] == level input bits (level1,level2,level3)
wire ld_ras_about
= (radr_cyc | (cadr_cyc & ~cas_cyc));
wire ld_cas_about
= ((cadr_cyc & cas_cyc) | hold_cyc);
//2.0: fix iotlb_err for pn129
//wire iotlb_err = (iotlb_enable & (ld_ras_about | ld_cas_about) & iotlb_miss & ~oe_off);
//wire iotlb_err = (iotlb_enable & iotlb_miss & data_cyc & ~data_cyc1);
wire dma_err = (iotlb_enable & iotlb_miss & data_cyc & ~data_cyc1) |
afx_perr;
wire dma_sel_17_12
= ( ~iotlb_enable | iotlb_miss | iotlb_rd_out[0] );
wire dma_sel_23_18
= ( ~iotlb_enable | iotlb_miss | iotlb_rd_out[1] );
wire dma_sel_27_24
= ( ~iotlb_enable | iotlb_miss | iotlb_rd_out[2] );
// wire dma_sel_17_12 = ( ~iotlb_enable | iotlb_miss | ~iotlb_valid | iotlb_lvl3 );
// wire dma_sel_23_18 = ( ~iotlb_enable | iotlb_miss | ~iotlb_valid | iotlb_lvl2 );
// wire dma_sel_27_24 = ( ~iotlb_enable | iotlb_miss | ~iotlb_valid | iotlb_lvl1 );
//2.0: add dp_perr[1:0] in bits iotlb_err_address[2:1] & renamed
//wire [31:0] iotlb_err_address = ({dma_addr[31:2],1'b0,dma_read});
wire [31:0] dma_err_address = ({dma_addr[31:3],memif_perr[1:0],dma_read});
wire [27:12] xdma_addr
;
always @(posedge gclk)
begin
if (~reset_l)
begin
iotlb_cd_out_reg <= #1 32'h00000000;
iotlb_rd_out_reg <= #1 32'h00000000;
end
else if (iotlb_cntl_wrt_d3)
begin
iotlb_cd_out_reg <= #1 ({iotlb_cd_out[39:32],iotlb_cd_out[30:25],iotlb_cd_out[23:18],
8'h00,iotlb_cd_out[41:40],iotlb_cd_out[31],iotlb_cd_out[24]});
iotlb_rd_out_reg <= #1 ({4'b0000,iotlb_rd_out});
end
end
always @(posedge gclk)
begin
if (~reset_l)
begin
This page: |
Created: | Thu Aug 19 11:59:54 1999 |
| From: |
../../../sparc_v8/ssparc/pcic/afxmaster/rtl/afxmaster.v
|