Commit | Line | Data |
---|---|---|
86530b38 AT |
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 |