| // ========== Copyright Header Begin ========================================== |
| // |
| // OpenSPARC T1 Processor File: spu_mast.v |
| // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. |
| // |
| // The above named program is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU General Public |
| // License version 2 as published by the Free Software Foundation. |
| // |
| // The above named program 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 |
| // General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public |
| // License along with this work; if not, write to the Free Software |
| // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. |
| // |
| // ========== Copyright Header End ============================================ |
| //////////////////////////////////////////////////////////////////////// |
| /* |
| // Description: state machine to do stores to L2. |
| */ |
| //////////////////////////////////////////////////////////////////////// |
| |
| module spu_mast ( |
| |
| /*outputs*/ |
| spu_mast_maaddr_addrinc, |
| spu_mast_memren, |
| spu_mast_stbuf_wen, |
| spu_mast_mpa_addrinc, |
| spu_mast_streq, |
| |
| spu_mast_done_set, |
| /*inputs*/ |
| |
| spu_mactl_iss_pulse_dly, |
| mactl_stop, |
| streq_ack, |
| len_neqz, |
| |
| spu_wen_allma_stacks_ok, |
| |
| spu_mactl_perr_set, |
| |
| spu_mactl_stxa_force_abort, |
| |
| se, |
| reset, |
| rclk); |
| |
| |
| input reset; |
| input rclk; |
| input se; |
| |
| input spu_mactl_iss_pulse_dly; |
| input mactl_stop; |
| input streq_ack; |
| input len_neqz; |
| |
| input spu_wen_allma_stacks_ok; |
| |
| input spu_mactl_perr_set; |
| |
| input spu_mactl_stxa_force_abort; |
| // ----------------------------------------------------------------- |
| |
| output spu_mast_maaddr_addrinc; |
| output spu_mast_memren; |
| output spu_mast_stbuf_wen; |
| output spu_mast_mpa_addrinc; |
| output spu_mast_streq; |
| output spu_mast_done_set; |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| wire spu_mast_st_done,tr2rdmem_frm_wait4stdrain; |
| |
| wire ok_to_signal_cmplt; |
| |
| wire start_set; |
| wire spu_mast_allow_rdmem; |
| |
| wire [1:0] rd_cntr_add,rd_cntr_q; |
| |
| wire tr2laststreq_frm_wait4stdrain; |
| |
| wire local_kill_abort; |
| // ----------------------------------------------------------------- |
| wire streq_ack_dly; |
| dff_s #(1) streq_ack_ff ( |
| .din(streq_ack) , |
| .q(streq_ack_dly), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| // we need a state set to indcate st is done, and when an |
| // masync gets issued later, then the load asi is returned. |
| wire spu_mast_done_wen = (spu_mast_st_done | local_kill_abort) & mactl_stop; |
| wire spu_mast_done_rst = reset | spu_mactl_iss_pulse_dly; |
| |
| wire spu_mast_done_set_q; |
| |
| dffre_s #(1) spu_mast_done_ff ( |
| .din(1'b1) , |
| .q(spu_mast_done_set_q), |
| .en(spu_mast_done_wen), |
| .rst(spu_mast_done_rst), .clk (rclk), .se(se), .si(), .so()); |
| |
| assign spu_mast_done_set = spu_mast_done_set_q & ok_to_signal_cmplt; |
| |
| |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| |
| // added the following dly to fix bug5212. I had added a flop to lsu_spu_ldst_ack to |
| // the logic to increment the store req in spu_wen ack_cmplt counter to prevent |
| // introducing a timing path. Now in the case if an ma_store has a length 1, then |
| // the done_set gets asserted a cycle before the store ack incrementer increments. |
| // So now i have to delay the done_set by a cycle so that the incrementer has |
| // seen a store request by that time and the counter is no longer zero. |
| wire spu_mast_done_wen_dly; |
| dff_s #(1) spu_mast_done_wen_ff ( |
| .din(spu_mast_done_wen) , |
| .q(spu_mast_done_wen_dly), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| dffre_s #(1) spu_mast_done_stack_ff ( |
| .din(1'b1) , |
| .q(spu_mast_done_set_stack), |
| .en(spu_mast_done_wen_dly), |
| .rst(spu_mast_done_rst), .clk (rclk), .se(se), .si(), .so()); |
| |
| assign ok_to_signal_cmplt = spu_wen_allma_stacks_ok & spu_mast_done_set_stack; |
| |
| |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| // ----------------------------------------------------------------- |
| wire state_reset = reset | local_kill_abort; |
| // ------------------------------------------------------------------------- |
| dff_s #(1) idle_state_ff ( |
| .din(nxt_idle_state) , |
| .q(cur_idle_state), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| dffr_s #(1) rdmem_state_ff ( |
| .din(nxt_rdmem_state) , |
| .q(cur_rdmem_state), |
| .rst(state_reset), .clk (rclk), .se(se), .si(), .so()); |
| |
| dffr_s #(1) wait4stdrain_state_ff ( |
| .din(nxt_wait4stdrain_state) , |
| .q(cur_wait4stdrain_state), |
| .rst(state_reset), .clk (rclk), .se(se), .si(), .so()); |
| |
| dffr_s #(1) laststreq_state_ff ( |
| .din(nxt_laststreq_state) , |
| .q(cur_laststreq_state), |
| .rst(state_reset), .clk (rclk), .se(se), .si(), .so()); |
| |
| // ------------------------------------------------------------------------- |
| // ------------------------------------------------------------------------- |
| wire start_stop = spu_mactl_iss_pulse_dly & mactl_stop; |
| |
| // ------------------------------------------------------------------------- |
| // transition to idle state. |
| |
| /* |
| assign spu_mast_st_done = cur_wait4stdrain_state & streq_ack & |
| (~len_neqz | spu_mactl_stxa_force_abort); |
| */ |
| |
| |
| assign spu_mast_st_done = |
| //((cur_wait4stdrain_state & ~len_neqz & start_set) | |
| ((cur_wait4stdrain_state & ~len_neqz & rd_cntr_q[0]) | |
| cur_laststreq_state) & streq_ack ; |
| |
| |
| assign nxt_idle_state = ( |
| state_reset | spu_mast_st_done | |
| (cur_idle_state & ~start_stop)); |
| |
| |
| wire tr2rdmem_frm_idle = cur_idle_state & start_stop; |
| |
| // this delay is because spu_mast_memren is based on nxt_rdmem_state |
| // and it happens before cur_idle_state goes to zero. |
| wire dly_tr2rdmem_frm_idle; |
| dff_s #(1) dly_tr2rdmem_frm_idle_ff ( |
| .din(tr2rdmem_frm_idle) , |
| .q(dly_tr2rdmem_frm_idle), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| // ------------------------------------------------------------------------- |
| // transition to rdmem state. |
| |
| |
| assign tr2rdmem_frm_wait4stdrain = cur_wait4stdrain_state & |
| (streq_ack | spu_mast_allow_rdmem) & |
| len_neqz ; |
| |
| assign nxt_rdmem_state = ( |
| (dly_tr2rdmem_frm_idle) | |
| (tr2rdmem_frm_wait4stdrain)); |
| |
| // ------------------------------------------------------------------------- |
| // transition to wait4stdrain state. |
| |
| assign nxt_wait4stdrain_state = ( |
| cur_rdmem_state | |
| (cur_wait4stdrain_state & ~(streq_ack | (spu_mast_allow_rdmem & |
| len_neqz)) )); |
| |
| // ------------------------------------------------------------------------- |
| // transition to laststreq state. |
| |
| assign tr2laststreq_frm_wait4stdrain = cur_wait4stdrain_state & streq_ack & ~len_neqz & |
| //~start_set; |
| ~rd_cntr_q[0]; |
| |
| assign nxt_laststreq_state = ( |
| tr2laststreq_frm_wait4stdrain | |
| (cur_laststreq_state & ~streq_ack) ); |
| |
| wire tr2laststreq_frm_wait4stdrain_dly; |
| dff_s #(1) tr2laststreq_frm_wait4stdrain_ff ( |
| .din(tr2laststreq_frm_wait4stdrain) , |
| .q(tr2laststreq_frm_wait4stdrain_dly), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| // ------------------------------------------------------------------------- |
| // ------------------------------------------------------------------------- |
| // ------------------------------------------------------------------------- |
| |
| assign spu_mast_maaddr_addrinc = cur_rdmem_state; |
| |
| //assign spu_mast_memren = nxt_rdmem_state; |
| assign spu_mast_memren = cur_rdmem_state & ~local_kill_abort; |
| |
| wire cur_rdmem_state_dly; |
| dff_s #(1) cur_rdmem_state_ff ( |
| .din(cur_rdmem_state) , |
| .q(cur_rdmem_state_dly), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| wire cur_rdmem_state_dly2,cur_rdmem_state_dly3; |
| dff_s #(2) cur_rdmem_state_dly_ff ( |
| .din({cur_rdmem_state_dly,cur_rdmem_state_dly2}) , |
| .q({cur_rdmem_state_dly2,cur_rdmem_state_dly3}), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| assign spu_mast_stbuf_wen = cur_rdmem_state_dly; |
| |
| |
| // cannot use cur_rdmem_state to start the request since the data will |
| // not be in the store buffer till the next cyle after mem rd. |
| //assign spu_mast_streq = cur_wait4stdrain_state | cur_rdmem_state; |
| |
| |
| //assign spu_mast_streq = cur_wait4stdrain_state & ~spu_mactl_dly_streq & |
| assign spu_mast_streq = ((cur_rdmem_state_dly3 & start_set & ~rd_cntr_q[1]) | |
| (streq_ack_dly & len_neqz) | |
| (tr2laststreq_frm_wait4stdrain_dly) )& |
| ~cur_idle_state & ~spu_mactl_perr_set & |
| ~spu_mactl_stxa_force_abort; |
| // when perr is asserted |
| // the state machine to goto idle. but due to above eq, len is not zero and |
| // whith streq_ack it will continue doing streq and hence the st_ack counter keeps incr. |
| |
| |
| assign local_kill_abort = ((cur_rdmem_state_dly3 & start_set & ~rd_cntr_q[1]) | |
| (streq_ack_dly & len_neqz) | |
| (tr2laststreq_frm_wait4stdrain_dly) )& |
| (spu_mactl_perr_set | spu_mactl_stxa_force_abort); |
| |
| |
| wire tr2rdmem_frm_wait4stdrain_dly; |
| dff_s #(1) tr2rdmem_frm_wait4stdrain_ff ( |
| .din(tr2rdmem_frm_wait4stdrain) , |
| .q(tr2rdmem_frm_wait4stdrain_dly), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| wire tr2rdmem_frm_wait4stdrain_dly2; |
| dff_s #(1) tr2rdmem_frm_wait4stdrain_dly_ff ( |
| .din(tr2rdmem_frm_wait4stdrain_dly) , |
| .q(tr2rdmem_frm_wait4stdrain_dly2), |
| .clk (rclk), .se(se), .si(), .so()); |
| |
| assign spu_mast_mpa_addrinc = tr2rdmem_frm_wait4stdrain_dly2; |
| |
| |
| // ------------------------------------------------------------------------- |
| // ------------------------------------------------------------------------- |
| // ------------------------------------------------------------------------- |
| // cntr to do an extra st req. |
| |
| wire rd_cntr_en = cur_rdmem_state; |
| |
| wire rd_cntr_rst = state_reset | streq_ack_dly | start_stop; |
| |
| assign rd_cntr_add[1:0] = rd_cntr_q[1:0] + 2'b01; |
| |
| dffre_s #(2) rd_cntr_ff ( |
| .din(rd_cntr_add[1:0]) , |
| .q(rd_cntr_q[1:0]), |
| .en(rd_cntr_en), |
| .rst(rd_cntr_rst), .clk (rclk), .se(se), .si(), .so()); |
| |
| |
| dffre_s #(1) start_stop_ff ( |
| .din(1'b1) , |
| .q(start_set), |
| .en(start_stop), |
| .rst(state_reset | streq_ack_dly), .clk (rclk), .se(se), .si(), .so()); |
| |
| |
| /* |
| assign spu_mast_allow_rdmem = (start_set & ~rd_cntr_q[1] & cur_rdmem_state_dly3) | |
| (~start_set & rd_cntr_q[0]) ; |
| */ |
| |
| |
| assign spu_mast_allow_rdmem = (start_set & ~rd_cntr_q[1] & cur_rdmem_state_dly3) ; |
| //------------------------------------------------------------------ |
| |
| endmodule |