| // ========== Copyright Header Begin ========================================== | |
| // | |
| // OpenSPARC T1 Processor File: i2c_fctrl.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 ============================================ | |
| //////////////////////////////////////////////////////////////////////// | |
| /* | |
| // Module Name: i2c_fctrl (io-to-cpu fast control) | |
| // Description: | |
| */ | |
| //////////////////////////////////////////////////////////////////////// | |
| // Global header file includes | |
| //////////////////////////////////////////////////////////////////////// | |
| `include "sys.h" // system level definition file which contains the | |
| // time scale definition | |
| `include "iop.h" | |
| //////////////////////////////////////////////////////////////////////// | |
| // Local header file includes / local defines | |
| //////////////////////////////////////////////////////////////////////// | |
| //////////////////////////////////////////////////////////////////////// | |
| // Interface signal list declarations | |
| //////////////////////////////////////////////////////////////////////// | |
| module i2c_fctrl (/*AUTOARG*/ | |
| // Outputs | |
| int_buf_sel_next, io_buf_sel_next, int_buf_rd, io_buf_rd, | |
| int_buf_hit_hwm, io_buf_head_f, int_buf_wr, int_buf_tail_ptr, | |
| int_buf_head_ptr, io_buf_head_ptr, | |
| // Inputs | |
| cpu_rst_l, cpu_clk, tx_sync, rx_sync, cpx_iob_grant_cx2, | |
| int_buf_cpx_req, io_buf_cpx_req, iob_cpx_req_next, | |
| cpu_mondo_rd_d2, cpu_mondo_wr_d2, io_buf_tail_s | |
| ); | |
| //////////////////////////////////////////////////////////////////////// | |
| // Signal declarations | |
| //////////////////////////////////////////////////////////////////////// | |
| // Global interface | |
| input cpu_rst_l; | |
| input cpu_clk; | |
| input tx_sync; | |
| input rx_sync; | |
| // Crossbar interface | |
| input [`IOB_CPU_WIDTH-1:0] cpx_iob_grant_cx2; | |
| // i2c fast datapath interface | |
| input [`IOB_CPU_WIDTH-1:0] int_buf_cpx_req; | |
| input [`IOB_CPU_WIDTH-1:0] io_buf_cpx_req; | |
| input [`IOB_CPU_WIDTH-1:0] iob_cpx_req_next; | |
| output int_buf_sel_next; | |
| output io_buf_sel_next; | |
| output int_buf_rd; | |
| output io_buf_rd; | |
| // c2i fast control interface | |
| input cpu_mondo_rd_d2; | |
| input cpu_mondo_wr_d2; | |
| output int_buf_hit_hwm; | |
| // i2c slow control interface | |
| input [`IOB_IO_BUF_INDEX:0] io_buf_tail_s; | |
| output [`IOB_IO_BUF_INDEX:0] io_buf_head_f; | |
| // Interrupt table read result buffer interface | |
| output int_buf_wr; | |
| output [`IOB_INT_BUF_INDEX-1:0] int_buf_tail_ptr; | |
| output [`IOB_INT_BUF_INDEX-1:0] int_buf_head_ptr; | |
| // IO buffer interface | |
| output [`IOB_IO_BUF_INDEX-1:0] io_buf_head_ptr; | |
| // Internal signals | |
| wire [`IOB_CPU_WIDTH-1:0] cpx_buf_full; | |
| wire [`IOB_CPU_WIDTH-1:0] cpx_iob_grant; | |
| wire cpu_mondo_rdwr_d2; | |
| wire [`IOB_INT_BUF_INDEX:0] int_buf_tail; | |
| wire [`IOB_INT_BUF_INDEX:0] int_buf_tail_plus; | |
| wire [`IOB_INT_BUF_INDEX:0] int_buf_tail_plus10; | |
| wire [`IOB_INT_BUF_INDEX:0] int_buf_head; | |
| wire [`IOB_INT_BUF_INDEX:0] int_buf_head_prev; | |
| wire [`IOB_INT_BUF_INDEX:0] int_buf_head_plus1; | |
| wire int_buf_head_inc; | |
| wire int_buf_empty; | |
| wire int_buf_empty_prev; | |
| wire int_buf_vld; | |
| wire int_buf_vld_next; | |
| wire [`IOB_IO_BUF_INDEX:0] io_buf_head; | |
| wire [`IOB_IO_BUF_INDEX:0] io_buf_head_prev; | |
| wire [`IOB_IO_BUF_INDEX:0] io_buf_head_plus1; | |
| wire io_buf_head_inc; | |
| wire [`IOB_IO_BUF_INDEX:0] io_buf_tail; | |
| wire io_buf_empty; | |
| wire io_buf_empty_prev; | |
| wire io_buf_vld; | |
| wire io_buf_vld_next; | |
| //////////////////////////////////////////////////////////////////////// | |
| // Code starts here | |
| //////////////////////////////////////////////////////////////////////// | |
| /************************************************************ | |
| * IO-to-CPX Mux Control | |
| ************************************************************/ | |
| // Generate mux selects | |
| assign int_buf_sel_next = ~|(cpx_buf_full & ~cpx_iob_grant & int_buf_cpx_req) & | |
| int_buf_vld; | |
| assign io_buf_sel_next = ~|(cpx_buf_full & ~cpx_iob_grant & io_buf_cpx_req) & | |
| ~int_buf_sel_next & io_buf_vld; | |
| /************************************************************ | |
| * Flop grant from CPX | |
| ************************************************************/ | |
| dffrl_ns #(`IOB_CPU_WIDTH) cpx_iob_grant_ff (.din(cpx_iob_grant_cx2), | |
| .clk(cpu_clk), | |
| .rst_l(cpu_rst_l), | |
| .q(cpx_iob_grant)); | |
| /************************************************************ | |
| * Counters to keep track of each CPX's buffer level | |
| ************************************************************/ | |
| // CPX0 Count | |
| i2c_cpx_cnt count0 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[0]), | |
| .cpx_iob_grant(cpx_iob_grant[0]), | |
| .cpx_buf_full(cpx_buf_full[0])); | |
| // CPX1 Count | |
| i2c_cpx_cnt count1 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[1]), | |
| .cpx_iob_grant(cpx_iob_grant[1]), | |
| .cpx_buf_full(cpx_buf_full[1])); | |
| // CPX2 Count | |
| i2c_cpx_cnt count2 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[2]), | |
| .cpx_iob_grant(cpx_iob_grant[2]), | |
| .cpx_buf_full(cpx_buf_full[2])); | |
| // CPX3 Count | |
| i2c_cpx_cnt count3 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[3]), | |
| .cpx_iob_grant(cpx_iob_grant[3]), | |
| .cpx_buf_full(cpx_buf_full[3])); | |
| // CPX4 Count | |
| i2c_cpx_cnt count4 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[4]), | |
| .cpx_iob_grant(cpx_iob_grant[4]), | |
| .cpx_buf_full(cpx_buf_full[4])); | |
| // CPX5 Count | |
| i2c_cpx_cnt count5 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[5]), | |
| .cpx_iob_grant(cpx_iob_grant[5]), | |
| .cpx_buf_full(cpx_buf_full[5])); | |
| // CPX6 Count | |
| i2c_cpx_cnt count6 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[6]), | |
| .cpx_iob_grant(cpx_iob_grant[6]), | |
| .cpx_buf_full(cpx_buf_full[6])); | |
| // CPX7 Count | |
| i2c_cpx_cnt count7 (.rst_l(cpu_rst_l), | |
| .clk(cpu_clk), | |
| .iob_cpx_req_next(iob_cpx_req_next[7]), | |
| .cpx_iob_grant(cpx_iob_grant[7]), | |
| .cpx_buf_full(cpx_buf_full[7])); | |
| /************************************************************ | |
| * Interrupt Status Table Read Result Buffer Control | |
| * An 16 deep buffer to store interrupt table read results. | |
| * | |
| * __decode int stat table read | |
| * flop req | | |
| * | | __read int stat table here | |
| * | | | | |
| * | | | __flop read result | |
| * | | | | | |
| * | | | | __tail pointer increment | |
| * | | | | | | |
| * | | | | | compute hwm __stall sent here | |
| * | | | | | | | | |
| * V V V V d2 V V V | |
| * PQ PA PX1 rptr PX2 C1 C2 C3 C4 C5 rptr | |
| * PQ PA PX1 rptr PX2 C1 C2 C3 C4 C5 rptr | |
| * PQ PA PX1 rptr PX2 C1 C2 C3 C4 | |
| * PQ PA PX1 rptr PX2 C1 C2 C3 | |
| * PQ PA PX1 rptr PX2 C1 C2 | |
| * PQ PA PX1 rptr PX2 C1 | |
| * PQ PA PX1 rptr PX2 | |
| * PQ PA PX1 rptr | |
| * PQ PA PX1 rptr | |
| * PQ PA PX1 rptr | |
| * PQ PA PX1 | |
| * --> PQ | |
| * | | |
| * | | |
| * packet in this PQ is stalled | |
| * | |
| * When stall is signalled, there can potentially be 10 packets in C4, C3, | |
| * C2, C1, PX2, rptr, PX1, PA, PQ, and PQ-1 that need to be queued in the CPU shared buffer. | |
| ************************************************************/ | |
| assign cpu_mondo_rdwr_d2 = cpu_mondo_rd_d2 | cpu_mondo_wr_d2; | |
| assign int_buf_wr = cpu_mondo_rdwr_d2; | |
| // Tail pointer to interrupt table read result buffer | |
| dffrle_ns #(`IOB_INT_BUF_INDEX+1) int_buf_tail_ff (.din(int_buf_tail_plus), | |
| .rst_l(cpu_rst_l), | |
| .en(int_buf_wr), | |
| .clk(cpu_clk), | |
| .q(int_buf_tail)); | |
| assign int_buf_tail_plus = int_buf_tail + 5'b1; | |
| assign int_buf_tail_ptr = int_buf_tail[`IOB_INT_BUF_INDEX-1:0]; | |
| assign int_buf_tail_plus10 = int_buf_tail + 5'b01010; | |
| assign int_buf_hit_hwm = ((int_buf_tail_plus10[`IOB_INT_BUF_INDEX] != int_buf_head[`IOB_INT_BUF_INDEX]) & | |
| (int_buf_tail_plus10[`IOB_INT_BUF_INDEX-1:0] >= int_buf_head[`IOB_INT_BUF_INDEX-1:0])) | | |
| ((int_buf_tail_plus10[`IOB_INT_BUF_INDEX] == int_buf_head[`IOB_INT_BUF_INDEX]) & | |
| (int_buf_tail_plus10[`IOB_INT_BUF_INDEX-1:0] <= int_buf_head[`IOB_INT_BUF_INDEX-1:0])); | |
| // Head pointer to interrupt table read result buffer | |
| dffrl_ns #(`IOB_INT_BUF_INDEX+1) int_buf_head_prev_ff (.din(int_buf_head), | |
| .clk(cpu_clk), | |
| .rst_l(cpu_rst_l), | |
| .q(int_buf_head_prev)); | |
| assign int_buf_head_plus1 = int_buf_head_prev + 4'b1; | |
| assign int_buf_head = int_buf_head_inc ? int_buf_head_plus1 : | |
| int_buf_head_prev; | |
| assign int_buf_head_ptr = int_buf_head[`IOB_INT_BUF_INDEX-1:0]; | |
| // Interrupt table read result buffer is empty if head == tail | |
| assign int_buf_empty = (int_buf_head == int_buf_tail); | |
| dff_ns #(1) int_buf_empty_prev_ff (.din(int_buf_empty|~cpu_rst_l), | |
| .clk(cpu_clk), | |
| .q(int_buf_empty_prev)); | |
| assign int_buf_head_inc = ~int_buf_empty_prev & | |
| ((int_buf_vld & int_buf_sel_next) | | |
| ~int_buf_vld); | |
| // This read signal corresponds to the access already in the memory | |
| assign int_buf_rd = int_buf_head_inc; | |
| assign int_buf_vld_next = int_buf_rd | | |
| (int_buf_vld & ~int_buf_sel_next); | |
| dffrl_ns #(1) int_buf_vld_ff (.din(int_buf_vld_next), | |
| .clk(cpu_clk), | |
| .rst_l(cpu_rst_l), | |
| .q(int_buf_vld)); | |
| /************************************************************ | |
| * IO Buffer Control | |
| ************************************************************/ | |
| // Head pointer to io buffer | |
| dffrl_ns #(`IOB_IO_BUF_INDEX+1) io_buf_head_prev_ff (.din(io_buf_head), | |
| .clk(cpu_clk), | |
| .rst_l(cpu_rst_l), | |
| .q(io_buf_head_prev)); | |
| assign io_buf_head_plus1 = io_buf_head_prev + 5'b1; | |
| assign io_buf_head = io_buf_head_inc ? io_buf_head_plus1 : | |
| io_buf_head_prev; | |
| assign io_buf_head_ptr = io_buf_head[`IOB_IO_BUF_INDEX-1:0]; | |
| dffrle_ns #(`IOB_IO_BUF_INDEX+1) io_buf_head_f_ff (.din(io_buf_head), | |
| .rst_l(cpu_rst_l), | |
| .en(tx_sync), | |
| .clk(cpu_clk), | |
| .q(io_buf_head_f)); | |
| // Flop tail pointer once to convert to cpu clock domain | |
| dffrle_ns #(`IOB_IO_BUF_INDEX+1) io_buf_tail_ff (.din(io_buf_tail_s), | |
| .rst_l(cpu_rst_l), | |
| .en(rx_sync), | |
| .clk(cpu_clk), | |
| .q(io_buf_tail)); | |
| // IO buffer is empty if head == tail | |
| assign io_buf_empty = (io_buf_head == io_buf_tail); | |
| dff_ns #(1) io_buf_empty_prev_ff (.din(io_buf_empty|~cpu_rst_l), | |
| .clk(cpu_clk), | |
| .q(io_buf_empty_prev)); | |
| assign io_buf_head_inc = ~io_buf_empty_prev & | |
| ((io_buf_vld & io_buf_sel_next) | | |
| ~io_buf_vld); | |
| // This read signal corresponds to the access already in the memory | |
| assign io_buf_rd = io_buf_head_inc; | |
| assign io_buf_vld_next = io_buf_rd | | |
| (io_buf_vld & ~io_buf_sel_next); | |
| dffrl_ns #(1) io_buf_vld_ff (.din(io_buf_vld_next), | |
| .clk(cpu_clk), | |
| .rst_l(cpu_rst_l), | |
| .q(io_buf_vld)); | |
| endmodule // i2c_fctrl | |