| 1 | // ========== Copyright Header Begin ========================================== |
| 2 | // |
| 3 | // OpenSPARC T2 Processor File: niu_siu_interface.cpp |
| 4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved |
| 5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
| 6 | // |
| 7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 8 | // |
| 9 | // This program is free software; you can redistribute it and/or modify |
| 10 | // it under the terms of the GNU General Public License as published by |
| 11 | // the Free Software Foundation; version 2 of the License. |
| 12 | // |
| 13 | // This program is distributed in the hope that it will be useful, |
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | // GNU General Public License for more details. |
| 17 | // |
| 18 | // You should have received a copy of the GNU General Public License |
| 19 | // along with this program; if not, write to the Free Software |
| 20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | // |
| 22 | // For the avoidance of doubt, and except that if any non-GPL license |
| 23 | // choice is available it will apply instead, Sun elects to use only |
| 24 | // the General Public License version 2 (GPLv2) at this time for any |
| 25 | // software where a choice of GPL license versions is made |
| 26 | // available with the language indicating that GPLv2 or any later version |
| 27 | // may be used, or where a choice of which version of the GPL is applied is |
| 28 | // otherwise unspecified. |
| 29 | // |
| 30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 31 | // CA 95054 USA or visit www.sun.com if you need additional information or |
| 32 | // have any questions. |
| 33 | // |
| 34 | // ========== Copyright Header End ============================================ |
| 35 | // ========== Copyright Header Begin ========================================== |
| 36 | // |
| 37 | // OpenSPARC T2 Processor File: niu_siu_interface.cpp |
| 38 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved |
| 39 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
| 40 | // |
| 41 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 42 | // |
| 43 | // This program is free software; you can redistribute it and/or modify |
| 44 | // it under the terms of the GNU General Public License as published by |
| 45 | // the Free Software Foundation; version 2 of the License. |
| 46 | // |
| 47 | // This program is distributed in the hope that it will be useful, |
| 48 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 49 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 50 | // GNU General Public License for more details. |
| 51 | // |
| 52 | // You should have received a copy of the GNU General Public License |
| 53 | // along with this program; if not, write to the Free Software |
| 54 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 55 | // |
| 56 | // For the avoidance of doubt, and except that if any non-GPL license |
| 57 | // choice is available it will apply instead, Sun elects to use only |
| 58 | // the General Public License version 2 (GPLv2) at this time for any |
| 59 | // software where a choice of GPL license versions is made |
| 60 | // available with the language indicating that GPLv2 or any later version |
| 61 | // may be used, or where a choice of which version of the GPL is applied is |
| 62 | // otherwise unspecified. |
| 63 | // |
| 64 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 65 | // CA 95054 USA or visit www.sun.com if you need additional information or |
| 66 | // have any questions. |
| 67 | // |
| 68 | // ========== Copyright Header End ============================================ |
| 69 | #include <systemc.h> |
| 70 | #include "niu_debug_functions.h" |
| 71 | |
| 72 | #include "niu_siu_interface.h" |
| 73 | #include "sharedmem.h" |
| 74 | |
| 75 | |
| 76 | extern sharedmem *shmem; |
| 77 | |
| 78 | |
| 79 | niu_siu_interface::niu_siu_interface(sc_module_name) { |
| 80 | SC_METHOD(sii_interface); |
| 81 | sensitive << clk.pos(); |
| 82 | SC_METHOD(sio_interface); |
| 83 | sensitive << clk.pos(); |
| 84 | |
| 85 | sii_bypass_credit = 16; |
| 86 | sii_ordered_credit = 16; |
| 87 | sii_request_id = 0; //16-bit request ID |
| 88 | |
| 89 | wr_packet_state = 0; |
| 90 | wr_busy = false; |
| 91 | rd_busy = false; |
| 92 | chunks = 0; |
| 93 | reset = 1; |
| 94 | } |
| 95 | |
| 96 | |
| 97 | void niu_siu_interface::ecc16(sc_lv<16> id, sc_lv<6> &ecc) { |
| 98 | ecc[0] = id[0] ^ id[1] ^ id[3] ^ id[4] ^ id[6] ^ id[8] ^ id[10] ^ id[11] ^ id[13] ^ id[15]; |
| 99 | ecc[1] = id[0] ^ id[2] ^ id[3] ^ id[5] ^ id[6] ^ id[9] ^ id[10] ^ id[12] ^ id[13]; |
| 100 | ecc[2] = id[1] ^ id[2] ^ id[3] ^ id[7] ^ id[8] ^ id[9] ^ id[10] ^ id[14] ^ id[15]; |
| 101 | ecc[3] = id[4] ^ id[5] ^ id[6] ^ id[7] ^ id[8] ^ id[9] ^ id[10]; |
| 102 | ecc[4] = id[11] ^ id[12] ^ id[13] ^ id[14] ^ id[15]; |
| 103 | ecc[5]= id[0] ^ id[1] ^ id[2] ^ id[3] ^ ecc[0] ^ ecc[1] ^ ecc[2]; |
| 104 | } |
| 105 | |
| 106 | void niu_siu_interface::pa_parity_n(sc_lv<40> addr, sc_lv<2> &aparity) { |
| 107 | aparity[0] = ~addr[ 0] ^ addr[ 2] ^ addr[ 4] ^ addr[ 6] ^ addr[ 8] ^ addr[10] ^ addr[12] ^ |
| 108 | addr[14] ^ addr[16] ^ addr[18] ^ addr[20] ^ addr[22] ^ addr[24] ^ addr[26] ^ |
| 109 | addr[28] ^ addr[30] ^ addr[32] ^ addr[34] ^ addr[36] ^ addr[38]; |
| 110 | aparity[1] = ~addr[ 1] ^ addr[ 3] ^ addr[ 5] ^ addr[ 7] ^ addr[ 9] ^ addr[11] ^ addr[13] ^ |
| 111 | addr[15] ^ addr[17] ^ addr[19] ^ addr[21] ^ addr[23] ^ addr[25] ^ addr[27] ^ |
| 112 | addr[29] ^ addr[31] ^ addr[33] ^ addr[35] ^ addr[37] ^ addr[39]; |
| 113 | } |
| 114 | |
| 115 | |
| 116 | |
| 117 | void niu_siu_interface::formHeader(uint64_t paddr, int write, sc_lv<128> &niu_sii_packet) { |
| 118 | sc_lv<6> command; |
| 119 | if(write) command = "010010"; else command = "001010"; |
| 120 | sc_lv<37> reserved1 = 0; |
| 121 | sc_lv<2> aparity; |
| 122 | sc_lv<1> timeout = "0"; |
| 123 | sc_lv<1> unmapped = "0"; |
| 124 | sc_lv<1> uncorrectable = "0"; |
| 125 | sc_lv<16> id; |
| 126 | id.set_cword(0, 0); |
| 127 | id.set_word(0, ++sii_request_id); |
| 128 | sc_lv<1> reserved2 = "0"; |
| 129 | sc_lv<1> cparity; |
| 130 | cparity[0] = ~command[0] ^ command[1] ^ command[2] ^ command[3] ^ command[4] ^ command[5]; |
| 131 | sc_lv<6> ctagecc; |
| 132 | sc_lv<16> reserved3 = 0; |
| 133 | sc_lv<40> pa; |
| 134 | pa.set_cword(0, 0); |
| 135 | pa.set_cword(1, 0); |
| 136 | pa.set_word(0, paddr & 0xffffffff); |
| 137 | pa.set_word(1, (paddr >> 32) & 0xffffffff); |
| 138 | ecc16(id, ctagecc); |
| 139 | pa_parity_n(pa, aparity); |
| 140 | |
| 141 | niu_sii_packet.range(127, 122) = command; |
| 142 | niu_sii_packet.range(121, 85) = reserved1; |
| 143 | niu_sii_packet.range(84, 83) = aparity; |
| 144 | niu_sii_packet.range(82, 82) = timeout; |
| 145 | niu_sii_packet.range(81, 81) = unmapped; |
| 146 | niu_sii_packet.range(80, 80) = uncorrectable; |
| 147 | niu_sii_packet.range(79, 64) = id; |
| 148 | niu_sii_packet.range(63, 63) = reserved2; |
| 149 | niu_sii_packet.range(62, 62) = cparity; |
| 150 | niu_sii_packet.range(61, 56) = ctagecc; |
| 151 | niu_sii_packet.range(55, 40) = reserved3; |
| 152 | niu_sii_packet.range(39, 0) = pa; |
| 153 | |
| 154 | cout << command << reserved1 << aparity << timeout << unmapped << uncorrectable << id << reserved2 << cparity << ctagecc << reserved3 << pa << endl; |
| 155 | //niu_sii_packet = command, reserved1, timeout,unmapped, uncorrectable, id, reserved2, cparity, ctagecc, reserved3, pa; |
| 156 | cout << niu_sii_packet << endl; |
| 157 | } |
| 158 | |
| 159 | void niu_siu_interface::formDataPacket(unsigned char *data, sc_lv<128> &niu_sii_packet, sc_lv<8> &niu_sii_parity) { |
| 160 | int parity = 0; |
| 161 | for(int i=0;i<8;i++) { |
| 162 | int parity_bit = 1; |
| 163 | for(int j=0;j<16;j++) { |
| 164 | int bit = (i/2) * 32 + (i % 2) + j * 2; |
| 165 | parity_bit ^= (data[15 - (bit / 8)] >> (bit % 8)) & 0x1; |
| 166 | } |
| 167 | parity |= parity_bit << i; |
| 168 | } |
| 169 | niu_sii_parity.set_cword(0, 0); |
| 170 | niu_sii_parity.set_word(0, parity); |
| 171 | |
| 172 | for(int i=0;i<4; i++) { |
| 173 | unsigned int word = 0; |
| 174 | for(int j=0;j<4; j++) word = (word << 8) + *data++; |
| 175 | niu_sii_packet.set_cword(3-i, 0); |
| 176 | niu_sii_packet.set_word(3-i, word); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | |
| 181 | void niu_siu_interface::sii_interface() { |
| 182 | if(reset) { |
| 183 | niu_sii_data.write(0); |
| 184 | niu_sii_parity.write(0); |
| 185 | niu_sii_datareq.write(false); |
| 186 | niu_sii_hdr_vld.write(false); |
| 187 | niu_sii_reqbypass.write(false); |
| 188 | niu_sio_dq.write(false); |
| 189 | reset = 0; |
| 190 | } |
| 191 | |
| 192 | //Check queue credits |
| 193 | if(sii_niu_bqdq.read()) sii_bypass_credit++; |
| 194 | if(sii_niu_oqdq.read()) sii_ordered_credit++; |
| 195 | if((sii_bypass_credit > 16) || (sii_bypass_credit < 0)) { |
| 196 | fprintf(stderr, "niu_siu_interface::sii_interface - incorrect value for sii_bypass_credit = %d\n", sii_bypass_credit); |
| 197 | exit(1); |
| 198 | } |
| 199 | if((sii_ordered_credit > 16) || (sii_ordered_credit < 0)) { |
| 200 | fprintf(stderr, "niu_siu_interface::sii_interface - incorrect value for sii_ordered_credit = %d\n", sii_ordered_credit); |
| 201 | exit(1); |
| 202 | } |
| 203 | |
| 204 | //There could be simultaneous read & write requests due to sp_sii_wr_available/sp_sii_rd_available |
| 205 | //If read in progress, do not let write to start, or if write is in progress, do not let read to start |
| 206 | |
| 207 | |
| 208 | //Process READ request here... |
| 209 | if(shmem) |
| 210 | if(wr_busy == false) |
| 211 | if(shmem->sii_receive_read_req(rd_addr, rd_size)) { |
| 212 | //printf("SII READ REQUEST: %llx %llx\n", rd_addr, rd_size); |
| 213 | rd_frag = rd_addr % 64; //handle unaligned read requests |
| 214 | rd_size_mod = rd_size + rd_frag; |
| 215 | rd_addr_itr = rd_addr; |
| 216 | rd_busy = true; |
| 217 | rd_request_chunks = 0; |
| 218 | } |
| 219 | if(rd_busy) { |
| 220 | if(rd_addr_itr < (rd_addr + rd_size_mod)) { |
| 221 | //printf("SII READ: RD_ADDR_ITR: %llx %llx %llx %llx\n", rd_addr_itr, rd_addr, rd_size_mod, rd_addr + rd_size_mod); |
| 222 | if(sii_ordered_credit > 0) { |
| 223 | sc_lv<128> niu_sii_packet; |
| 224 | formHeader(rd_addr_itr, 0, niu_sii_packet); |
| 225 | rd_request_ids[rd_request_chunks++] = sii_request_id; //keep track of the request IDs |
| 226 | niu_sii_data.write(niu_sii_packet); |
| 227 | niu_sii_hdr_vld.write(true); |
| 228 | sii_ordered_credit--; |
| 229 | rd_addr_itr = (rd_addr_itr + 64) & 0xFFFFFFFFFFFFFFC0ull ; //align to 64-byte boundary |
| 230 | } else { |
| 231 | niu_sii_hdr_vld.write(false); |
| 232 | } |
| 233 | } else { |
| 234 | rd_busy = false; |
| 235 | niu_sii_hdr_vld.write(false); |
| 236 | return; |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | |
| 241 | //Process Write Requests here |
| 242 | if(shmem) |
| 243 | if(rd_busy == false) |
| 244 | if(shmem->sii_receive_write_req(wr_addr, wr_data, wr_size)) { |
| 245 | //Need to form the request; |
| 246 | //For each 64-byte, head + 4 x 128 bits data |
| 247 | //Figure out data parity computation |
| 248 | //If size is larger than 64 bytes, need to have multiple requests |
| 249 | //Keep track of the credit as well; no more than 16 requests |
| 250 | //Cannot get a new request while processing one; sp_siu_available... |
| 251 | wr_busy = true; |
| 252 | wr_addr_itr = wr_addr; |
| 253 | wr_packet_state = 1; //5 per 64-byte chunk |
| 254 | } |
| 255 | //Need to handle credits here... |
| 256 | if(wr_busy) { |
| 257 | //printf("NIU WRITE: State:%d ITR=%llx ADDR=%llx SIZE=%llx\n", wr_packet_state, wr_addr_itr, wr_addr, wr_size); |
| 258 | if(wr_packet_state == 1) { //header cycle |
| 259 | if(sii_ordered_credit >0) { |
| 260 | sc_lv<128> niu_sii_packet; |
| 261 | formHeader(wr_addr_itr, 1, niu_sii_packet); |
| 262 | niu_sii_data.write(niu_sii_packet); |
| 263 | niu_sii_hdr_vld.write(true); |
| 264 | niu_sii_datareq.write(true); |
| 265 | sii_ordered_credit--; |
| 266 | wr_packet_state++; |
| 267 | } |
| 268 | } else if(wr_packet_state == 6) { |
| 269 | //done with the write |
| 270 | wr_busy = false; |
| 271 | wr_packet_state = 0; |
| 272 | niu_sii_parity.write("00000000"); |
| 273 | niu_sii_data.write(0); |
| 274 | shmem->sii_write_res(); |
| 275 | } else { //data cycle |
| 276 | sc_lv<128> niu_sii_packet; |
| 277 | sc_lv<8> parity; |
| 278 | formDataPacket(&wr_data[wr_addr_itr - wr_addr + (wr_packet_state - 2) * 16], niu_sii_packet, parity); |
| 279 | niu_sii_data.write(niu_sii_packet); |
| 280 | niu_sii_parity.write(parity); |
| 281 | niu_sii_hdr_vld.write(false); |
| 282 | niu_sii_datareq.write(false); |
| 283 | wr_packet_state++; |
| 284 | if(wr_packet_state == 6) { |
| 285 | wr_addr_itr += 64; |
| 286 | if(wr_addr_itr < (wr_addr + wr_size)) { |
| 287 | wr_packet_state = 1; //go to the next chunk on the next cycle |
| 288 | } |
| 289 | } |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | |
| 295 | void niu_siu_interface::sio_interface() { |
| 296 | |
| 297 | if(chunks != 0) { |
| 298 | sio_data[4-chunks] = sio_niu_data.read(); |
| 299 | if(chunks == 1) { |
| 300 | //received the complete packet; return the data back to sam niu model |
| 301 | niu_sio_dq.write(true); //dequeue |
| 302 | uint8_t data[64]; |
| 303 | for(int i=0;i<4;i++) { |
| 304 | for(int j=0;j<4;j++) { |
| 305 | for(int k=0;k<4;k++) { |
| 306 | unsigned int word = sio_data[i].get_word(j); |
| 307 | data[i*16+15 - (j*4+k)] = (word >> (k*8)) & 0xff; |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | //printf("RD_PTR: %d\n", rd_ptr); |
| 312 | int rd_vl_data_size = (rd_ptr == 0) ? 64 - rd_frag : 64; |
| 313 | if(rd_ptr != 0) rd_ptr -= rd_frag; |
| 314 | for(int i=0;i<rd_vl_data_size;i++) rd_response[rd_ptr + i] = data[i]; |
| 315 | |
| 316 | int flag = 1; |
| 317 | //printf("READ REQUEST IDS: "); |
| 318 | for(int i=0;i<rd_request_chunks;i++) { |
| 319 | //printf("%d ", rd_request_ids[i]); |
| 320 | if(rd_request_ids[i] != -1) { |
| 321 | flag = 0; |
| 322 | break; |
| 323 | } |
| 324 | } |
| 325 | //printf("\n"); |
| 326 | if(flag) { |
| 327 | niu_debug_hex_dump("SIO Data Return", rd_response, rd_size); |
| 328 | shmem->sii_read_res(rd_response, rd_size); |
| 329 | } |
| 330 | } |
| 331 | chunks--; |
| 332 | } else |
| 333 | niu_sio_dq.write(false); |
| 334 | |
| 335 | //A read response is received |
| 336 | if(sio_niu_hdr_vld.read() & sio_niu_datareq.read()) { |
| 337 | //printf("SIO Header valid\n"); |
| 338 | sio_header = sio_niu_data.read(); |
| 339 | response_id = sio_header.range(79,64).get_word(0); |
| 340 | rd_ptr = -1; |
| 341 | for(int i=0;i<rd_request_chunks;i++) { |
| 342 | if(rd_request_ids[i] == response_id) { |
| 343 | rd_ptr = i * 64; |
| 344 | rd_request_ids[i] = -1; |
| 345 | break; |
| 346 | } |
| 347 | } |
| 348 | if(rd_ptr == -1) { |
| 349 | printf("niu_siu_interface::sio_interface - incorrect response_id = %d\n", response_id); |
| 350 | exit(1); |
| 351 | } |
| 352 | chunks = 4; |
| 353 | } |
| 354 | } |
| 355 | |
| 356 | |