| 1 | // ========== Copyright Header Begin ========================================== |
| 2 | // |
| 3 | // OpenSPARC T2 Processor File: N2_FrfEcc.cc |
| 4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. |
| 6 | // |
| 7 | // The above named program is free software; you can redistribute it and/or |
| 8 | // modify it under the terms of the GNU General Public |
| 9 | // License version 2 as published by the Free Software Foundation. |
| 10 | // |
| 11 | // The above named program is distributed in the hope that it will be |
| 12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | // General Public License for more details. |
| 15 | // |
| 16 | // You should have received a copy of the GNU General Public |
| 17 | // License along with this work; if not, write to the Free Software |
| 18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. |
| 19 | // |
| 20 | // ========== Copyright Header End ============================================ |
| 21 | /************************************************************************ |
| 22 | ** |
| 23 | ** Copyright (C) 2006, Sun Microsystems, Inc. |
| 24 | ** |
| 25 | ** Sun considers its source code as an unpublished, proprietary |
| 26 | ** trade secret and it is available only under strict license provisions. |
| 27 | ** This copyright notice is placed here only to protect Sun in the event |
| 28 | ** the source is deemed a published work. Disassembly, decompilation, |
| 29 | ** or other means of reducing the object code to human readable form |
| 30 | ** is prohibited by the license agreement under which this code is |
| 31 | ** provided to the user or company in possession of this copy. |
| 32 | ** |
| 33 | *************************************************************************/ |
| 34 | |
| 35 | #include "N2_Core.h" |
| 36 | #include "N2_Strand.h" |
| 37 | #include "N2_FrfEcc.h" |
| 38 | #include "BL_Hamming_32_7_Synd.h" |
| 39 | |
| 40 | // This routine injects errors into single precision registers in FRF if and |
| 41 | // only if the "ene" & "frcu" bits are set in the error injection register |
| 42 | extern "C" SS_Vaddr n2_frf_ras_inject(SS_Vaddr pc, |
| 43 | SS_Vaddr npc, |
| 44 | SS_Strand* s, |
| 45 | SS_Instr* i, |
| 46 | int reg_nr) |
| 47 | { |
| 48 | assert (reg_nr >= 0 && reg_nr < 64); |
| 49 | N2_Strand* n2_strand = (N2_Strand *)s; |
| 50 | N2_Core& n2_core = n2_strand->core; |
| 51 | |
| 52 | unsigned value = n2_strand->get_frf(SS_Strand::freg_idx2off(reg_nr)); |
| 53 | BL_EccBits ecc_obj = BL_Hamming_32_7_Synd::calc_check_bits(value); |
| 54 | unsigned ecc = ecc_obj.get(); |
| 55 | if ((n2_core.error_inject.ene()) && (n2_core.error_inject.frcu())) |
| 56 | { |
| 57 | ecc ^= n2_core.error_inject.eccmask(); |
| 58 | } |
| 59 | ecc_obj.set(ecc); |
| 60 | n2_strand->frf_ecc[reg_nr] = ecc_obj; |
| 61 | return 0; // Not sure if this is the right value to return |
| 62 | } |
| 63 | |
| 64 | // This routine injects errors into double precision registers in FRF |
| 65 | extern "C" SS_Vaddr n2_frf_dp_ras_inject(SS_Vaddr pc, |
| 66 | SS_Vaddr npc, |
| 67 | SS_Strand* s, |
| 68 | SS_Instr* i, |
| 69 | int reg_nr) |
| 70 | { |
| 71 | n2_frf_ras_inject(pc,npc,s,i,reg_nr); |
| 72 | n2_frf_ras_inject(pc,npc,s,i,(reg_nr + 1)); |
| 73 | return 0; |
| 74 | } |
| 75 | |
| 76 | // This method detects any errors (injected or otherwise), associtated |
| 77 | // with single precision registers in FRF |
| 78 | extern "C" SS_Vaddr n2_frf_ras_detect(SS_Vaddr pc, |
| 79 | SS_Vaddr npc, |
| 80 | SS_Strand* s, |
| 81 | SS_Instr* i, |
| 82 | int reg_nr) |
| 83 | { |
| 84 | return n2_frf_ras_detect_wrapper(pc,npc,s,i,reg_nr,0); |
| 85 | } |
| 86 | |
| 87 | // This method detects any errors (injected or otherwise), associtated |
| 88 | // with double precision registers in FRF |
| 89 | extern "C" SS_Vaddr n2_frf_dp_ras_detect(SS_Vaddr pc, |
| 90 | SS_Vaddr npc, |
| 91 | SS_Strand* s, |
| 92 | SS_Instr* i, |
| 93 | int reg_nr) |
| 94 | { |
| 95 | assert(!s->sim_state.trap_taken()); |
| 96 | SS_Vaddr trap_pc = n2_frf_ras_detect_wrapper(pc,npc,s,i,reg_nr,1); |
| 97 | if (s->sim_state.trap_taken()) |
| 98 | return trap_pc; |
| 99 | else |
| 100 | return n2_frf_ras_detect_wrapper(pc,npc,s,i,(reg_nr + 1),0); |
| 101 | } |
| 102 | |
| 103 | // The following routine is where the actual error detection for FRF occurs |
| 104 | // This routine is called by both the Single and double precision variants |
| 105 | // of error detectors |
| 106 | // The parameter 'bit_significance' determines if this register contains the |
| 107 | // least significant (31:0) bits or the most significant (63:32) bits. A value |
| 108 | // of 0 corresponds to LSB and a value of 1 corresponds to MSB. For single |
| 109 | // precision registers, the bit_significance is always zero. |
| 110 | // NOTE: This parameter has got nothing to do with the register number (ever or |
| 111 | // odd), but rather deals with the content. Usually for double precision values, |
| 112 | // a even numbered register will have MSB and an odd numbered register will have |
| 113 | // the LSB. But for single precision values, there is no such correspondance |
| 114 | // between register number and content and hence the need for this additional |
| 115 | // parameter |
| 116 | extern "C" SS_Vaddr n2_frf_ras_detect_wrapper(SS_Vaddr pc, |
| 117 | SS_Vaddr npc, |
| 118 | SS_Strand* s, |
| 119 | SS_Instr* i, |
| 120 | int reg_nr, |
| 121 | int bit_significance) |
| 122 | { |
| 123 | assert (reg_nr >= 0 && reg_nr < 64); |
| 124 | N2_Strand* n2_strand = (N2_Strand *)s; |
| 125 | N2_Core& n2_core = n2_strand->core; |
| 126 | |
| 127 | // Error Detection happens only if the FRF bit in CERER is set |
| 128 | if (n2_core.cerer.frf()) |
| 129 | { |
| 130 | unsigned value = n2_strand->get_frf(SS_Strand::freg_idx2off(reg_nr)); |
| 131 | BL_EccBits ecc_obj = n2_strand->frf_ecc[reg_nr]; |
| 132 | // Check if the ecc associated with this register is a valid ecc |
| 133 | if (ecc_obj.valid()) |
| 134 | { |
| 135 | // Syndrome is the difference between the stored and calculated ECC values |
| 136 | BL_Hamming_32_7_Synd syndrome = BL_Hamming_32_7_Synd(value,ecc_obj); |
| 137 | unsigned long long temp_reg = reg_nr; |
| 138 | // If the syndrome is not zero, then it means an ECC error has occured. |
| 139 | if (!syndrome.noError()) |
| 140 | { |
| 141 | // Errors are recorded only if the PSCCE bit is set in the SETER |
| 142 | if (n2_strand->seter.pscce()) |
| 143 | { |
| 144 | if (syndrome.isSingleBitError()) |
| 145 | n2_strand->data_sfsr.error_type(4); |
| 146 | else if (syndrome.isDoubleBitError() || syndrome.isMultipleBitError()) |
| 147 | n2_strand->data_sfsr.error_type(3); |
| 148 | unsigned long long native_add = 0; |
| 149 | unsigned long long intermediate_err_add; |
| 150 | // The syndrome of LSB (31:0) should be recorded in bits 12:6 of DSFAR |
| 151 | if (bit_significance == 0) |
| 152 | { |
| 153 | intermediate_err_add = (native_add & ~0x1fc0ULL) | |
| 154 | syndrome.getSyndrome() << 6; |
| 155 | } |
| 156 | // The syndrome of MSB (63:32) should be recorded in bits 19:13 of DSFAR |
| 157 | else if (bit_significance == 1) |
| 158 | { |
| 159 | intermediate_err_add = (native_add & ~0xfe000ULL) | |
| 160 | syndrome.getSyndrome() << 13; |
| 161 | } |
| 162 | // Capture the register number in bits 5:0 of DSFAR |
| 163 | unsigned long long error_add = (intermediate_err_add & ~0x3fULL) | |
| 164 | temp_reg; |
| 165 | n2_strand->data_sfar.error_addr(error_add); |
| 166 | return (s->trap)(pc,npc,s,i,SS_Trap::INTERNAL_PROCESSOR_ERROR); |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | // If the ecc associated with the register is invalid |
| 171 | else |
| 172 | { |
| 173 | // Not sure what the exact functioning should be in this case |
| 174 | // Should we calculate clean ecc and associate it with this reg (as in Riesling) |
| 175 | // unsigned ecc = N2_EccFile::calc_n2_FRF_checks(value); |
| 176 | // setECC(reg, ecc); |
| 177 | // Or should the program just call it quits! |
| 178 | // cerr << " Invalid ECC: Aborting!" << endl; |
| 179 | // exit(-1); |
| 180 | } |
| 181 | } |
| 182 | } |