1package xiangshan.backend.fu 2 3import chisel3._ 4import chisel3.ExcitingUtils.{ConnectionType, Debug} 5import chisel3.util._ 6import utils._ 7import xiangshan._ 8import xiangshan.backend._ 9import xiangshan.backend.fu.util._ 10import xiangshan.backend.roq.RoqExceptionInfo 11 12object hartId extends (() => Int) { 13 var x = 0 14 def apply(): Int = { 15 x = x + 1 16 x-1 17 } 18} 19 20trait HasExceptionNO { 21 def instrAddrMisaligned = 0 22 def instrAccessFault = 1 23 def illegalInstr = 2 24 def breakPoint = 3 25 def loadAddrMisaligned = 4 26 def loadAccessFault = 5 27 def storeAddrMisaligned = 6 28 def storeAccessFault = 7 29 def ecallU = 8 30 def ecallS = 9 31 def ecallM = 11 32 def instrPageFault = 12 33 def loadPageFault = 13 34 def storePageFault = 15 35 36 val ExcPriority = Seq( 37 breakPoint, // TODO: different BP has different priority 38 instrPageFault, 39 instrAccessFault, 40 illegalInstr, 41 instrAddrMisaligned, 42 ecallM, ecallS, ecallU, 43 storePageFault, 44 loadPageFault, 45 storeAccessFault, 46 loadAccessFault, 47 storeAddrMisaligned, 48 loadAddrMisaligned 49 ) 50 val frontendSet = List( 51 // instrAddrMisaligned, 52 instrAccessFault, 53 illegalInstr, 54 instrPageFault 55 ) 56 val csrSet = List( 57 illegalInstr, 58 breakPoint, 59 ecallU, 60 ecallS, 61 ecallM 62 ) 63 val loadUnitSet = List( 64 loadAddrMisaligned, 65 loadAccessFault, 66 loadPageFault 67 ) 68 val storeUnitSet = List( 69 storeAddrMisaligned, 70 storeAccessFault, 71 storePageFault 72 ) 73 val atomicsUnitSet = (loadUnitSet ++ storeUnitSet).distinct 74 val allPossibleSet = (frontendSet ++ csrSet ++ loadUnitSet ++ storeUnitSet).distinct 75 val csrWbCount = (0 until 16).map(i => if (csrSet.contains(i)) 1 else 0) 76 val loadWbCount = (0 until 16).map(i => if (loadUnitSet.contains(i)) 1 else 0) 77 val storeWbCount = (0 until 16).map(i => if (storeUnitSet.contains(i)) 1 else 0) 78 val atomicsWbCount = (0 until 16).map(i => if (atomicsUnitSet.contains(i)) 1 else 0) 79 val writebackCount = (0 until 16).map(i => csrWbCount(i) + atomicsWbCount(i) + loadWbCount(i) + 2 * storeWbCount(i)) 80 def partialSelect(vec: Vec[Bool], select: Seq[Int], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = { 81 if (dontCareBits) { 82 val new_vec = Wire(ExceptionVec()) 83 new_vec := DontCare 84 select.map(i => new_vec(i) := vec(i)) 85 return new_vec 86 } 87 else if (falseBits) { 88 val new_vec = Wire(ExceptionVec()) 89 new_vec.map(_ := false.B) 90 select.map(i => new_vec(i) := vec(i)) 91 return new_vec 92 } 93 else { 94 val new_vec = Wire(Vec(select.length, Bool())) 95 select.zipWithIndex.map{ case(s, i) => new_vec(i) := vec(s) } 96 return new_vec 97 } 98 } 99 def selectFrontend(vec: Vec[Bool], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = 100 partialSelect(vec, frontendSet, dontCareBits, falseBits) 101 def selectCSR(vec: Vec[Bool], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = 102 partialSelect(vec, csrSet, dontCareBits, falseBits) 103 def selectLoad(vec: Vec[Bool], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = 104 partialSelect(vec, loadUnitSet, dontCareBits, falseBits) 105 def selectStore(vec: Vec[Bool], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = 106 partialSelect(vec, storeUnitSet, dontCareBits, falseBits) 107 def selectAtomics(vec: Vec[Bool], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = 108 partialSelect(vec, atomicsUnitSet, dontCareBits, falseBits) 109 def selectAll(vec: Vec[Bool], dontCareBits: Boolean = true, falseBits: Boolean = false): Vec[Bool] = 110 partialSelect(vec, allPossibleSet, dontCareBits, falseBits) 111} 112 113class FpuCsrIO extends XSBundle { 114 val fflags = Output(Valid(UInt(5.W))) 115 val isIllegal = Output(Bool()) 116 val dirty_fs = Output(Bool()) 117 val frm = Input(UInt(3.W)) 118} 119 120 121class PerfCounterIO extends XSBundle { 122 val retiredInstr = Input(UInt(3.W)) 123 val value = Input(UInt(XLEN.W)) 124} 125 126class CSR extends FunctionUnit with HasCSRConst 127{ 128 val csrio = IO(new Bundle { 129 // output (for func === CSROpType.jmp) 130 val perf = new PerfCounterIO 131 val isPerfCnt = Output(Bool()) 132 // to FPU 133 val fpu = Flipped(new FpuCsrIO) 134 // from rob 135 val exception = Flipped(ValidIO(new RoqExceptionInfo)) 136 // to ROB 137 val isXRet = Output(Bool()) 138 val trapTarget = Output(UInt(VAddrBits.W)) 139 val interrupt = Output(Bool()) 140 // from LSQ 141 val memExceptionVAddr = Input(UInt(VAddrBits.W)) 142 // from outside cpu,externalInterrupt 143 val externalInterrupt = new ExternalInterruptIO 144 // TLB 145 val tlb = Output(new TlbCsrBundle) 146 }) 147 val difftestIO = IO(new Bundle() { 148 val intrNO = Output(UInt(64.W)) 149 val cause = Output(UInt(64.W)) 150 val priviledgeMode = Output(UInt(2.W)) 151 val mstatus = Output(UInt(64.W)) 152 val sstatus = Output(UInt(64.W)) 153 val mepc = Output(UInt(64.W)) 154 val sepc = Output(UInt(64.W)) 155 val mtval = Output(UInt(64.W)) 156 val stval = Output(UInt(64.W)) 157 val mtvec = Output(UInt(64.W)) 158 val stvec = Output(UInt(64.W)) 159 val mcause = Output(UInt(64.W)) 160 val scause = Output(UInt(64.W)) 161 val satp = Output(UInt(64.W)) 162 val mip = Output(UInt(64.W)) 163 val mie = Output(UInt(64.W)) 164 val mscratch = Output(UInt(64.W)) 165 val sscratch = Output(UInt(64.W)) 166 val mideleg = Output(UInt(64.W)) 167 val medeleg = Output(UInt(64.W)) 168 }) 169 difftestIO <> DontCare 170 171 val cfIn = io.in.bits.uop.cf 172 val cfOut = Wire(new CtrlFlow) 173 cfOut := cfIn 174 val flushPipe = Wire(Bool()) 175 176 val (valid, src1, src2, func) = ( 177 io.in.valid, 178 io.in.bits.src(0), 179 io.in.bits.uop.ctrl.imm, 180 io.in.bits.uop.ctrl.fuOpType 181 ) 182 183 // CSR define 184 185 class Priv extends Bundle { 186 val m = Output(Bool()) 187 val h = Output(Bool()) 188 val s = Output(Bool()) 189 val u = Output(Bool()) 190 } 191 192 val csrNotImplemented = RegInit(UInt(XLEN.W), 0.U) 193 194 class MstatusStruct extends Bundle { 195 val sd = Output(UInt(1.W)) 196 197 val pad1 = if (XLEN == 64) Output(UInt(27.W)) else null 198 val sxl = if (XLEN == 64) Output(UInt(2.W)) else null 199 val uxl = if (XLEN == 64) Output(UInt(2.W)) else null 200 val pad0 = if (XLEN == 64) Output(UInt(9.W)) else Output(UInt(8.W)) 201 202 val tsr = Output(UInt(1.W)) 203 val tw = Output(UInt(1.W)) 204 val tvm = Output(UInt(1.W)) 205 val mxr = Output(UInt(1.W)) 206 val sum = Output(UInt(1.W)) 207 val mprv = Output(UInt(1.W)) 208 val xs = Output(UInt(2.W)) 209 val fs = Output(UInt(2.W)) 210 val mpp = Output(UInt(2.W)) 211 val hpp = Output(UInt(2.W)) 212 val spp = Output(UInt(1.W)) 213 val pie = new Priv 214 val ie = new Priv 215 assert(this.getWidth == XLEN) 216 } 217 218 class SatpStruct extends Bundle { 219 val mode = UInt(4.W) 220 val asid = UInt(16.W) 221 val ppn = UInt(44.W) 222 } 223 224 class Interrupt extends Bundle { 225 val e = new Priv 226 val t = new Priv 227 val s = new Priv 228 } 229 230 // Machine-Level CSRs 231 232 val mtvec = RegInit(UInt(XLEN.W), 0.U) 233 val mcounteren = RegInit(UInt(XLEN.W), 0.U) 234 val mcause = RegInit(UInt(XLEN.W), 0.U) 235 val mtval = RegInit(UInt(XLEN.W), 0.U) 236 val mepc = Reg(UInt(XLEN.W)) 237 238 val mie = RegInit(0.U(XLEN.W)) 239 val mipWire = WireInit(0.U.asTypeOf(new Interrupt)) 240 val mipReg = RegInit(0.U.asTypeOf(new Interrupt).asUInt) 241 val mipFixMask = GenMask(9) | GenMask(5) | GenMask(1) 242 val mip = (mipWire.asUInt | mipReg).asTypeOf(new Interrupt) 243 244 def getMisaMxl(mxl: Int): UInt = {mxl.U << (XLEN-2)}.asUInt() 245 def getMisaExt(ext: Char): UInt = {1.U << (ext.toInt - 'a'.toInt)}.asUInt() 246 var extList = List('a', 's', 'i', 'u') 247 if (HasMExtension) { extList = extList :+ 'm' } 248 if (HasCExtension) { extList = extList :+ 'c' } 249 if (HasFPU) { extList = extList ++ List('f', 'd') } 250 val misaInitVal = getMisaMxl(2) | extList.foldLeft(0.U)((sum, i) => sum | getMisaExt(i)) //"h8000000000141105".U 251 val misa = RegInit(UInt(XLEN.W), misaInitVal) 252 253 // MXL = 2 | 0 | EXT = b 00 0000 0100 0001 0001 0000 0101 254 // (XLEN-1, XLEN-2) | |(25, 0) ZY XWVU TSRQ PONM LKJI HGFE DCBA 255 256 val mvendorid = RegInit(UInt(XLEN.W), 0.U) // this is a non-commercial implementation 257 val marchid = RegInit(UInt(XLEN.W), 0.U) // return 0 to indicate the field is not implemented 258 val mimpid = RegInit(UInt(XLEN.W), 0.U) // provides a unique encoding of the version of the processor implementation 259 val mhartNo = hartId() 260 val mhartid = RegInit(UInt(XLEN.W), mhartNo.asUInt) // the hardware thread running the code 261 val mstatus = RegInit(UInt(XLEN.W), 0.U) 262 263 // mstatus Value Table 264 // | sd | 265 // | pad1 | 266 // | sxl | hardlinked to 10, use 00 to pass xv6 test 267 // | uxl | hardlinked to 00 268 // | pad0 | 269 // | tsr | 270 // | tw | 271 // | tvm | 272 // | mxr | 273 // | sum | 274 // | mprv | 275 // | xs | 00 | 276 // | fs | 00 | 277 // | mpp | 00 | 278 // | hpp | 00 | 279 // | spp | 0 | 280 // | pie | 0000 | pie.h is used as UBE 281 // | ie | 0000 | uie hardlinked to 0, as N ext is not implemented 282 283 val mstatusStruct = mstatus.asTypeOf(new MstatusStruct) 284 def mstatusUpdateSideEffect(mstatus: UInt): UInt = { 285 val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct)) 286 val mstatusNew = Cat(mstatusOld.xs === "b11".U || mstatusOld.fs === "b11".U, mstatus(XLEN-2, 0)) 287 mstatusNew 288 } 289 290 val mstatusMask = (~ZeroExt(( 291 GenMask(XLEN-2, 38) | GenMask(31, 23) | GenMask(10, 9) | GenMask(2) | 292 GenMask(37) | // MBE 293 GenMask(36) | // SBE 294 GenMask(6) // UBE 295 ), 64)).asUInt() 296 297 val medeleg = RegInit(UInt(XLEN.W), 0.U) 298 val mideleg = RegInit(UInt(XLEN.W), 0.U) 299 val mscratch = RegInit(UInt(XLEN.W), 0.U) 300 301 val pmpcfg0 = RegInit(UInt(XLEN.W), 0.U) 302 val pmpcfg1 = RegInit(UInt(XLEN.W), 0.U) 303 val pmpcfg2 = RegInit(UInt(XLEN.W), 0.U) 304 val pmpcfg3 = RegInit(UInt(XLEN.W), 0.U) 305 val pmpaddr0 = RegInit(UInt(XLEN.W), 0.U) 306 val pmpaddr1 = RegInit(UInt(XLEN.W), 0.U) 307 val pmpaddr2 = RegInit(UInt(XLEN.W), 0.U) 308 val pmpaddr3 = RegInit(UInt(XLEN.W), 0.U) 309 310 // Superviser-Level CSRs 311 312 // val sstatus = RegInit(UInt(XLEN.W), "h00000000".U) 313 val sstatusWmask = "hc6122".U 314 // Sstatus Write Mask 315 // ------------------------------------------------------- 316 // 19 9 5 2 317 // 0 1100 0000 0001 0010 0010 318 // 0 c 0 1 2 2 319 // ------------------------------------------------------- 320 val sstatusRmask = sstatusWmask | "h8000000300018000".U 321 // Sstatus Read Mask = (SSTATUS_WMASK | (0xf << 13) | (1ull << 63) | (3ull << 32)) 322 val stvec = RegInit(UInt(XLEN.W), 0.U) 323 // val sie = RegInit(0.U(XLEN.W)) 324 val sieMask = "h222".U & mideleg 325 val sipMask = "h222".U & mideleg 326 val satp = RegInit(0.U(XLEN.W)) 327 // val satp = RegInit(UInt(XLEN.W), "h8000000000087fbe".U) // only use for tlb naive debug 328 val satpMask = "h80000fffffffffff".U // disable asid, mode can only be 8 / 0 329 val sepc = RegInit(UInt(XLEN.W), 0.U) 330 val scause = RegInit(UInt(XLEN.W), 0.U) 331 val stval = Reg(UInt(XLEN.W)) 332 val sscratch = RegInit(UInt(XLEN.W), 0.U) 333 val scounteren = RegInit(UInt(XLEN.W), 0.U) 334 335 val tlbBundle = Wire(new TlbCsrBundle) 336 tlbBundle.satp := satp.asTypeOf(new SatpStruct) 337 csrio.tlb := tlbBundle 338 339 // User-Level CSRs 340 val uepc = Reg(UInt(XLEN.W)) 341 342 // fcsr 343 class FcsrStruct extends Bundle { 344 val reserved = UInt((XLEN-3-5).W) 345 val frm = UInt(3.W) 346 val fflags = UInt(5.W) 347 assert(this.getWidth == XLEN) 348 } 349 val fcsr = RegInit(0.U(XLEN.W)) 350 // set mstatus->sd and mstatus->fs when true 351 val csrw_dirty_fp_state = WireInit(false.B) 352 353 def frm_wfn(wdata: UInt): UInt = { 354 val fcsrOld = WireInit(fcsr.asTypeOf(new FcsrStruct)) 355 csrw_dirty_fp_state := true.B 356 fcsrOld.frm := wdata(2,0) 357 fcsrOld.asUInt() 358 } 359 def frm_rfn(rdata: UInt): UInt = rdata(7,5) 360 361 def fflags_wfn(update: Boolean)(wdata: UInt): UInt = { 362 val fcsrOld = fcsr.asTypeOf(new FcsrStruct) 363 val fcsrNew = WireInit(fcsrOld) 364 csrw_dirty_fp_state := true.B 365 if (update) { 366 fcsrNew.fflags := wdata(4,0) | fcsrOld.fflags 367 } else { 368 fcsrNew.fflags := wdata(4,0) 369 } 370 fcsrNew.asUInt() 371 } 372 def fflags_rfn(rdata:UInt): UInt = rdata(4,0) 373 374 def fcsr_wfn(wdata: UInt): UInt = { 375 val fcsrOld = WireInit(fcsr.asTypeOf(new FcsrStruct)) 376 csrw_dirty_fp_state := true.B 377 Cat(fcsrOld.reserved, wdata.asTypeOf(fcsrOld).frm, wdata.asTypeOf(fcsrOld).fflags) 378 } 379 380 val fcsrMapping = Map( 381 MaskedRegMap(Fflags, fcsr, wfn = fflags_wfn(update = false), rfn = fflags_rfn), 382 MaskedRegMap(Frm, fcsr, wfn = frm_wfn, rfn = frm_rfn), 383 MaskedRegMap(Fcsr, fcsr, wfn = fcsr_wfn) 384 ) 385 386 // Atom LR/SC Control Bits 387 // val setLr = WireInit(Bool(), false.B) 388 // val setLrVal = WireInit(Bool(), false.B) 389 // val setLrAddr = WireInit(UInt(AddrBits.W), DontCare) //TODO : need check 390 // val lr = RegInit(Bool(), false.B) 391 // val lrAddr = RegInit(UInt(AddrBits.W), 0.U) 392 // 393 // when (setLr) { 394 // lr := setLrVal 395 // lrAddr := setLrAddr 396 // } 397 398 // Hart Priviledge Mode 399 val priviledgeMode = RegInit(UInt(2.W), ModeM) 400 401 // Emu perfcnt 402 val hasEmuPerfCnt = !env.FPGAPlatform 403 val nrEmuPerfCnts = if (hasEmuPerfCnt) 0x80 else 0x3 404 405 val emuPerfCnts = List.fill(nrEmuPerfCnts)(RegInit(0.U(XLEN.W))) 406 val emuPerfCntCond = List.fill(nrEmuPerfCnts)(WireInit(false.B)) 407 (emuPerfCnts zip emuPerfCntCond).map { case (c, e) => when (e) { c := c + 1.U } } 408 409 val emuPerfCntsLoMapping = (0 until nrEmuPerfCnts).map(i => MaskedRegMap(0x1000 + i, emuPerfCnts(i))) 410 val emuPerfCntsHiMapping = (0 until nrEmuPerfCnts).map(i => MaskedRegMap(0x1080 + i, emuPerfCnts(i)(63, 32))) 411 println(s"CSR: hasEmuPerfCnt:${hasEmuPerfCnt}") 412 413 // Perf Counter 414 val nrPerfCnts = 29 // 3...31 415 val perfCnts = List.fill(nrPerfCnts)(RegInit(0.U(XLEN.W))) 416 val perfEvents = List.fill(nrPerfCnts)(RegInit(0.U(XLEN.W))) 417 val mcountinhibit = RegInit(0.U(XLEN.W)) 418 val mcycle = RegInit(0.U(XLEN.W)) 419 mcycle := mcycle + 1.U 420 val minstret = RegInit(0.U(XLEN.W)) 421 minstret := minstret + RegNext(csrio.perf.retiredInstr) 422 423 // CSR reg map 424 val basicPrivMapping = Map( 425 426 //--- User Trap Setup --- 427 // MaskedRegMap(Ustatus, ustatus), 428 // MaskedRegMap(Uie, uie, 0.U, MaskedRegMap.Unwritable), 429 // MaskedRegMap(Utvec, utvec), 430 431 //--- User Trap Handling --- 432 // MaskedRegMap(Uscratch, uscratch), 433 // MaskedRegMap(Uepc, uepc), 434 // MaskedRegMap(Ucause, ucause), 435 // MaskedRegMap(Utval, utval), 436 // MaskedRegMap(Uip, uip), 437 438 //--- User Counter/Timers --- 439 // MaskedRegMap(Cycle, cycle), 440 // MaskedRegMap(Time, time), 441 // MaskedRegMap(Instret, instret), 442 443 //--- Supervisor Trap Setup --- 444 MaskedRegMap(Sstatus, mstatus, sstatusWmask, mstatusUpdateSideEffect, sstatusRmask), 445 // MaskedRegMap(Sedeleg, Sedeleg), 446 // MaskedRegMap(Sideleg, Sideleg), 447 MaskedRegMap(Sie, mie, sieMask, MaskedRegMap.NoSideEffect, sieMask), 448 MaskedRegMap(Stvec, stvec), 449 MaskedRegMap(Scounteren, scounteren), 450 451 //--- Supervisor Trap Handling --- 452 MaskedRegMap(Sscratch, sscratch), 453 MaskedRegMap(Sepc, sepc), 454 MaskedRegMap(Scause, scause), 455 MaskedRegMap(Stval, stval), 456 MaskedRegMap(Sip, mip.asUInt, sipMask, MaskedRegMap.Unwritable, sipMask), 457 458 //--- Supervisor Protection and Translation --- 459 MaskedRegMap(Satp, satp, satpMask, MaskedRegMap.NoSideEffect, satpMask), 460 461 //--- Machine Information Registers --- 462 MaskedRegMap(Mvendorid, mvendorid, 0.U, MaskedRegMap.Unwritable), 463 MaskedRegMap(Marchid, marchid, 0.U, MaskedRegMap.Unwritable), 464 MaskedRegMap(Mimpid, mimpid, 0.U, MaskedRegMap.Unwritable), 465 MaskedRegMap(Mhartid, mhartid, 0.U, MaskedRegMap.Unwritable), 466 467 //--- Machine Trap Setup --- 468 MaskedRegMap(Mstatus, mstatus, mstatusMask, mstatusUpdateSideEffect, mstatusMask), 469 MaskedRegMap(Misa, misa), // now MXL, EXT is not changeable 470 MaskedRegMap(Medeleg, medeleg, "hf3ff".U), 471 MaskedRegMap(Mideleg, mideleg, "h222".U), 472 MaskedRegMap(Mie, mie), 473 MaskedRegMap(Mtvec, mtvec), 474 MaskedRegMap(Mcounteren, mcounteren), 475 476 //--- Machine Trap Handling --- 477 MaskedRegMap(Mscratch, mscratch), 478 MaskedRegMap(Mepc, mepc), 479 MaskedRegMap(Mcause, mcause), 480 MaskedRegMap(Mtval, mtval), 481 MaskedRegMap(Mip, mip.asUInt, 0.U, MaskedRegMap.Unwritable), 482 ) 483 484 // PMP is unimplemented yet 485 val pmpMapping = Map( 486 MaskedRegMap(Pmpcfg0, pmpcfg0), 487 MaskedRegMap(Pmpcfg1, pmpcfg1), 488 MaskedRegMap(Pmpcfg2, pmpcfg2), 489 MaskedRegMap(Pmpcfg3, pmpcfg3), 490 MaskedRegMap(PmpaddrBase + 0, pmpaddr0), 491 MaskedRegMap(PmpaddrBase + 1, pmpaddr1), 492 MaskedRegMap(PmpaddrBase + 2, pmpaddr2), 493 MaskedRegMap(PmpaddrBase + 3, pmpaddr3) 494 ) 495 496 var perfCntMapping = Map( 497 MaskedRegMap(Mcountinhibit, mcountinhibit), 498 MaskedRegMap(Mcycle, mcycle), 499 MaskedRegMap(Minstret, minstret), 500 ) 501 val MhpmcounterStart = Mhpmcounter3 502 val MhpmeventStart = Mhpmevent3 503 for (i <- 0 until nrPerfCnts) { 504 perfCntMapping += MaskedRegMap(MhpmcounterStart + i, perfCnts(i)) 505 perfCntMapping += MaskedRegMap(MhpmeventStart + i, perfEvents(i)) 506 } 507 508 val mapping = basicPrivMapping ++ 509 perfCntMapping ++ 510 pmpMapping ++ 511 emuPerfCntsLoMapping ++ 512 (if (XLEN == 32) emuPerfCntsHiMapping else Nil) ++ 513 (if (HasFPU) fcsrMapping else Nil) 514 515 val addr = src2(11, 0) 516 val csri = ZeroExt(src2(16, 12), XLEN) 517 val rdata = Wire(UInt(XLEN.W)) 518 val wdata = LookupTree(func, List( 519 CSROpType.wrt -> src1, 520 CSROpType.set -> (rdata | src1), 521 CSROpType.clr -> (rdata & (~src1).asUInt()), 522 CSROpType.wrti -> csri, 523 CSROpType.seti -> (rdata | csri), 524 CSROpType.clri -> (rdata & (~csri).asUInt()) 525 )) 526 527 val addrInPerfCnt = (addr >= Mcycle.U) && (addr <= Mhpmcounter31.U) 528 csrio.isPerfCnt := addrInPerfCnt 529 530 // satp wen check 531 val satpLegalMode = (wdata.asTypeOf(new SatpStruct).mode===0.U) || (wdata.asTypeOf(new SatpStruct).mode===8.U) 532 533 // general CSR wen check 534 val wen = valid && func =/= CSROpType.jmp && (addr=/=Satp.U || satpLegalMode) 535 val modePermitted = csrAccessPermissionCheck(addr, false.B, priviledgeMode) 536 val perfcntPermitted = perfcntPermissionCheck(addr, priviledgeMode, mcounteren, scounteren) 537 val permitted = Mux(addrInPerfCnt, perfcntPermitted, modePermitted) 538 // Writeable check is ingored. 539 // Currently, write to illegal csr addr will be ignored 540 MaskedRegMap.generate(mapping, addr, rdata, wen && permitted, wdata) 541 io.out.bits.data := rdata 542 io.out.bits.uop := io.in.bits.uop 543 io.out.bits.uop.cf := cfOut 544 io.out.bits.uop.ctrl.flushPipe := flushPipe 545 546 // Fix Mip/Sip write 547 val fixMapping = Map( 548 MaskedRegMap(Mip, mipReg.asUInt, mipFixMask), 549 MaskedRegMap(Sip, mipReg.asUInt, sipMask, MaskedRegMap.NoSideEffect, sipMask) 550 ) 551 val rdataDummy = Wire(UInt(XLEN.W)) 552 MaskedRegMap.generate(fixMapping, addr, rdataDummy, wen, wdata) 553 554 when (csrio.fpu.fflags.valid) { 555 fcsr := fflags_wfn(update = true)(csrio.fpu.fflags.bits) 556 } 557 // set fs and sd in mstatus 558 when (csrw_dirty_fp_state || csrio.fpu.dirty_fs) { 559 val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct)) 560 mstatusNew.fs := "b11".U 561 mstatusNew.sd := true.B 562 mstatus := mstatusNew.asUInt() 563 } 564 csrio.fpu.frm := fcsr.asTypeOf(new FcsrStruct).frm 565 566 // CSR inst decode 567 val isEbreak = addr === privEbreak && func === CSROpType.jmp 568 val isEcall = addr === privEcall && func === CSROpType.jmp 569 val isMret = addr === privMret && func === CSROpType.jmp 570 val isSret = addr === privSret && func === CSROpType.jmp 571 val isUret = addr === privUret && func === CSROpType.jmp 572 573 XSDebug(wen, "csr write: pc %x addr %x rdata %x wdata %x func %x\n", cfIn.pc, addr, rdata, wdata, func) 574 XSDebug(wen, "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", cfIn.pc, mstatus, mideleg , medeleg, priviledgeMode) 575 576 // Illegal priviledged operation list 577 val illegalSModeSret = valid && isSret && priviledgeMode === ModeS && mstatusStruct.tsr.asBool 578 579 // Illegal priviledged instruction check 580 val isIllegalAddr = MaskedRegMap.isIllegalAddr(mapping, addr) 581 val isIllegalAccess = !permitted 582 val isIllegalPrivOp = illegalSModeSret 583 584 // def MMUPermissionCheck(ptev: Bool, pteu: Bool): Bool = ptev && !(priviledgeMode === ModeU && !pteu) && !(priviledgeMode === ModeS && pteu && mstatusStruct.sum.asBool) 585 // def MMUPermissionCheckLoad(ptev: Bool, pteu: Bool): Bool = ptev && !(priviledgeMode === ModeU && !pteu) && !(priviledgeMode === ModeS && pteu && mstatusStruct.sum.asBool) && (pter || (mstatusStruct.mxr && ptex)) 586 // imem 587 // val imemPtev = true.B 588 // val imemPteu = true.B 589 // val imemPtex = true.B 590 // val imemReq = true.B 591 // val imemPermissionCheckPassed = MMUPermissionCheck(imemPtev, imemPteu) 592 // val hasInstrPageFault = imemReq && !(imemPermissionCheckPassed && imemPtex) 593 // assert(!hasInstrPageFault) 594 595 // dmem 596 // val dmemPtev = true.B 597 // val dmemPteu = true.B 598 // val dmemReq = true.B 599 // val dmemPermissionCheckPassed = MMUPermissionCheck(dmemPtev, dmemPteu) 600 // val dmemIsStore = true.B 601 602 // val hasLoadPageFault = dmemReq && !dmemIsStore && !(dmemPermissionCheckPassed) 603 // val hasStorePageFault = dmemReq && dmemIsStore && !(dmemPermissionCheckPassed) 604 // assert(!hasLoadPageFault) 605 // assert(!hasStorePageFault) 606 607 //TODO: Havn't test if io.dmemMMU.priviledgeMode is correct yet 608 tlbBundle.priv.mxr := mstatusStruct.mxr.asBool 609 tlbBundle.priv.sum := mstatusStruct.sum.asBool 610 tlbBundle.priv.imode := priviledgeMode 611 tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode) 612 613 // Branch control 614 val retTarget = Wire(UInt(VAddrBits.W)) 615 val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed 616 flushPipe := resetSatp || (valid && func === CSROpType.jmp && !isEcall) 617 618 retTarget := DontCare 619 // val illegalEret = TODO 620 621 when (valid && isMret) { 622 val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct)) 623 val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct)) 624 mstatusNew.ie.m := mstatusOld.pie.m 625 priviledgeMode := mstatusOld.mpp 626 mstatusNew.pie.m := true.B 627 mstatusNew.mpp := ModeU 628 mstatusNew.mprv := 0.U 629 mstatus := mstatusNew.asUInt 630 // lr := false.B 631 retTarget := mepc(VAddrBits-1, 0) 632 } 633 634 when (valid && isSret && !illegalSModeSret) { 635 val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct)) 636 val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct)) 637 mstatusNew.ie.s := mstatusOld.pie.s 638 priviledgeMode := Cat(0.U(1.W), mstatusOld.spp) 639 mstatusNew.pie.s := true.B 640 mstatusNew.spp := ModeU 641 mstatus := mstatusNew.asUInt 642 mstatusNew.mprv := 0.U 643 // lr := false.B 644 retTarget := sepc(VAddrBits-1, 0) 645 } 646 647 when (valid && isUret) { 648 val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct)) 649 val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct)) 650 // mstatusNew.mpp.m := ModeU //TODO: add mode U 651 mstatusNew.ie.u := mstatusOld.pie.u 652 priviledgeMode := ModeU 653 mstatusNew.pie.u := true.B 654 mstatus := mstatusNew.asUInt 655 retTarget := uepc(VAddrBits-1, 0) 656 } 657 658 io.in.ready := true.B 659 io.out.valid := valid 660 661 val csrExceptionVec = WireInit(cfIn.exceptionVec) 662 csrExceptionVec(breakPoint) := io.in.valid && isEbreak 663 csrExceptionVec(ecallM) := priviledgeMode === ModeM && io.in.valid && isEcall 664 csrExceptionVec(ecallS) := priviledgeMode === ModeS && io.in.valid && isEcall 665 csrExceptionVec(ecallU) := priviledgeMode === ModeU && io.in.valid && isEcall 666 // Trigger an illegal instr exception when: 667 // * unimplemented csr is being read/written 668 // * csr access is illegal 669 csrExceptionVec(illegalInstr) := (isIllegalAddr || isIllegalAccess) && wen 670 cfOut.exceptionVec := csrExceptionVec 671 672 /** 673 * Exception and Intr 674 */ 675 val ideleg = (mideleg & mip.asUInt) 676 def priviledgedEnableDetect(x: Bool): Bool = Mux(x, ((priviledgeMode === ModeS) && mstatusStruct.ie.s) || (priviledgeMode < ModeS), 677 ((priviledgeMode === ModeM) && mstatusStruct.ie.m) || (priviledgeMode < ModeM)) 678 679 // send interrupt information to ROQ 680 val intrVecEnable = Wire(Vec(12, Bool())) 681 intrVecEnable.zip(ideleg.asBools).map{case(x,y) => x := priviledgedEnableDetect(y)} 682 val intrVec = mie(11,0) & mip.asUInt & intrVecEnable.asUInt 683 val intrBitSet = intrVec.orR() 684 csrio.interrupt := intrBitSet 685 mipWire.t.m := csrio.externalInterrupt.mtip 686 mipWire.s.m := csrio.externalInterrupt.msip 687 mipWire.e.m := csrio.externalInterrupt.meip 688 689 // interrupts 690 val intrNO = IntPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(intrVec(i), i.U, sum)) 691 val raiseIntr = csrio.exception.valid && csrio.exception.bits.isInterrupt 692 XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", csrio.exception.bits.uop.cf.pc, intrNO) 693 694 // exceptions 695 val raiseException = csrio.exception.valid && !csrio.exception.bits.isInterrupt 696 val hasInstrPageFault = csrio.exception.bits.uop.cf.exceptionVec(instrPageFault) && raiseException 697 val hasLoadPageFault = csrio.exception.bits.uop.cf.exceptionVec(loadPageFault) && raiseException 698 val hasStorePageFault = csrio.exception.bits.uop.cf.exceptionVec(storePageFault) && raiseException 699 val hasStoreAddrMisaligned = csrio.exception.bits.uop.cf.exceptionVec(storeAddrMisaligned) && raiseException 700 val hasLoadAddrMisaligned = csrio.exception.bits.uop.cf.exceptionVec(loadAddrMisaligned) && raiseException 701 val hasInstrAccessFault = csrio.exception.bits.uop.cf.exceptionVec(instrAccessFault) && raiseException 702 val hasLoadAccessFault = csrio.exception.bits.uop.cf.exceptionVec(loadAccessFault) && raiseException 703 val hasStoreAccessFault = csrio.exception.bits.uop.cf.exceptionVec(storeAccessFault) && raiseException 704 705 val raiseExceptionVec = csrio.exception.bits.uop.cf.exceptionVec 706 val exceptionNO = ExcPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(raiseExceptionVec(i), i.U, sum)) 707 val causeNO = (raiseIntr << (XLEN-1)).asUInt() | Mux(raiseIntr, intrNO, exceptionNO) 708 709 val raiseExceptionIntr = csrio.exception.valid 710 XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n", 711 csrio.exception.bits.uop.cf.pc, intrNO, intrVec, exceptionNO, raiseExceptionVec.asUInt 712 ) 713 XSDebug(raiseExceptionIntr, 714 "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", 715 csrio.exception.bits.uop.cf.pc, 716 mstatus, 717 mideleg, 718 medeleg, 719 priviledgeMode 720 ) 721 722 // mtval write logic 723 val memExceptionAddr = SignExt(csrio.memExceptionVAddr, XLEN) 724 when (hasInstrPageFault || hasLoadPageFault || hasStorePageFault) { 725 val tval = Mux( 726 hasInstrPageFault, 727 Mux( 728 csrio.exception.bits.uop.cf.crossPageIPFFix, 729 SignExt(csrio.exception.bits.uop.cf.pc + 2.U, XLEN), 730 SignExt(csrio.exception.bits.uop.cf.pc, XLEN) 731 ), 732 memExceptionAddr 733 ) 734 when (priviledgeMode === ModeM) { 735 mtval := tval 736 }.otherwise { 737 stval := tval 738 } 739 } 740 741 when (hasLoadAddrMisaligned || hasStoreAddrMisaligned) { 742 mtval := memExceptionAddr 743 } 744 745 val deleg = Mux(raiseIntr, mideleg , medeleg) 746 // val delegS = ((deleg & (1 << (causeNO & 0xf))) != 0) && (priviledgeMode < ModeM); 747 val delegS = deleg(causeNO(3,0)) && (priviledgeMode < ModeM) 748 val tvalWen = !(hasInstrPageFault || hasLoadPageFault || hasStorePageFault || hasLoadAddrMisaligned || hasStoreAddrMisaligned) || raiseIntr // TODO: need check 749 val isXRet = func === CSROpType.jmp && !isEcall 750 // ctrl block use these 2 cycles later 751 // 0 1 2 752 // XRet 753 // wb -> commit 754 // -> flush -> frontend redirect 755 csrio.isXRet := RegNext(RegNext(isXRet)) 756 csrio.trapTarget := Mux(RegNext(RegNext(isXRet)), 757 RegNext(RegNext(retTarget)), 758 Mux(delegS, stvec, mtvec)(VAddrBits-1, 0) 759 ) 760 761 when (raiseExceptionIntr) { 762 val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct)) 763 val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct)) 764 765 when (delegS) { 766 scause := causeNO 767 sepc := SignExt(csrio.exception.bits.uop.cf.pc, XLEN) 768 mstatusNew.spp := priviledgeMode 769 mstatusNew.pie.s := mstatusOld.ie.s 770 mstatusNew.ie.s := false.B 771 priviledgeMode := ModeS 772 when (tvalWen) { stval := 0.U } 773 }.otherwise { 774 mcause := causeNO 775 mepc := SignExt(csrio.exception.bits.uop.cf.pc, XLEN) 776 mstatusNew.mpp := priviledgeMode 777 mstatusNew.pie.m := mstatusOld.ie.m 778 mstatusNew.ie.m := false.B 779 priviledgeMode := ModeM 780 when (tvalWen) { mtval := 0.U } 781 } 782 783 mstatus := mstatusNew.asUInt 784 } 785 786 XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", cfIn.pc) 787 788 789 /** 790 * Emu Performance counters 791 */ 792 val emuPerfCntList = Map( 793 // "Mcycle" -> (0x1000, "perfCntCondMcycle" ), 794 // "Minstret" -> (0x1002, "perfCntCondMinstret" ), 795 "BpInstr" -> (0x1003, "perfCntCondBpInstr" ), 796 "BpRight" -> (0x1004, "perfCntCondBpRight" ), 797 "BpWrong" -> (0x1005, "perfCntCondBpWrong" ), 798 "BpBRight" -> (0x1006, "perfCntCondBpBRight"), 799 "BpBWrong" -> (0x1007, "perfCntCondBpBWrong"), 800 "BpJRight" -> (0x1008, "perfCntCondBpJRight"), 801 "BpJWrong" -> (0x1009, "perfCntCondBpJWrong"), 802 "BpIRight" -> (0x100a, "perfCntCondBpIRight"), 803 "BpIWrong" -> (0x100b, "perfCntCondBpIWrong"), 804 "BpRRight" -> (0x100c, "perfCntCondBpRRight"), 805 "BpRWrong" -> (0x100d, "perfCntCondBpRWrong"), 806 "RoqWalk" -> (0x100f, "perfCntCondRoqWalk" ), 807 "DTlbReqCnt0" -> (0x1015, "perfCntDtlbReqCnt0" ), 808 "DTlbReqCnt1" -> (0x1016, "perfCntDtlbReqCnt1" ), 809 "DTlbReqCnt2" -> (0x1017, "perfCntDtlbReqCnt2" ), 810 "DTlbReqCnt3" -> (0x1018, "perfCntDtlbReqCnt3" ), 811 "DTlbMissCnt0"-> (0x1019, "perfCntDtlbMissCnt0" ), 812 "DTlbMissCnt1"-> (0x1020, "perfCntDtlbMissCnt1" ), 813 "DTlbMissCnt2"-> (0x1021, "perfCntDtlbMissCnt2" ), 814 "DTlbMissCnt3"-> (0x1022, "perfCntDtlbMissCnt3" ), 815 "ITlbReqCnt0" -> (0x1023, "perfCntItlbReqCnt0" ), 816 "ITlbMissCnt0"-> (0x1024, "perfCntItlbMissCnt0" ), 817 "PtwReqCnt" -> (0x1025, "perfCntPtwReqCnt" ), 818 "PtwCycleCnt" -> (0x1026, "perfCntPtwCycleCnt" ), 819 "PtwL2TlbHit" -> (0x1027, "perfCntPtwL2TlbHit" ), 820 "ICacheReq" -> (0x1028, "perfCntIcacheReqCnt" ), 821 "ICacheMiss" -> (0x1029, "perfCntIcacheMissCnt"), 822 "ICacheMMIO" -> (0x102a, "perfCntIcacheMMIOCnt"), 823 // "FetchFromLoopBuffer" -> (0x102b, "CntFetchFromLoopBuffer"), 824 // "ExitLoop1" -> (0x102c, "CntExitLoop1"), 825 // "ExitLoop2" -> (0x102d, "CntExitLoop2"), 826 // "ExitLoop3" -> (0x102e, "CntExitLoop3") 827 828 "ubtbRight" -> (0x1030, "perfCntubtbRight"), 829 "ubtbWrong" -> (0x1031, "perfCntubtbWrong"), 830 "btbRight" -> (0x1032, "perfCntbtbRight"), 831 "btbWrong" -> (0x1033, "perfCntbtbWrong"), 832 "tageRight" -> (0x1034, "perfCnttageRight"), 833 "tageWrong" -> (0x1035, "perfCnttageWrong"), 834 "rasRight" -> (0x1036, "perfCntrasRight"), 835 "rasWrong" -> (0x1037, "perfCntrasWrong"), 836 "loopRight" -> (0x1038, "perfCntloopRight"), 837 "loopWrong" -> (0x1039, "perfCntloopWrong"), 838 "s1Right" -> (0x103a, "perfCntS1Right"), 839 "s1Wrong" -> (0x103b, "perfCntS1Wrong"), 840 "s2Right" -> (0x103c, "perfCntS2Right"), 841 "s2Wrong" -> (0x103d, "perfCntS2Wrong"), 842 "s3Right" -> (0x103e, "perfCntS3Right"), 843 "s3Wrong" -> (0x103f, "perfCntS3Wrong"), 844 "takenAndRight" -> (0x1040, "perfCntTakenAndRight"), 845 "takenButWrong" -> (0x1041, "perfCntTakenButWrong"), 846 // "L2cacheHit" -> (0x1023, "perfCntCondL2cacheHit") 847 ) ++ ( 848 (0 until dcacheParameters.nMissEntries).map(i => 849 ("DCacheMissQueuePenalty" + Integer.toString(i, 10), (0x1042 + i, "perfCntDCacheMissQueuePenaltyEntry" + Integer.toString(i, 10))) 850 ).toMap 851 ) ++ ( 852 (0 until icacheParameters.nMissEntries).map(i => 853 ("ICacheMissQueuePenalty" + Integer.toString(i, 10), (0x1042 + dcacheParameters.nMissEntries + i, "perfCntICacheMissQueuePenaltyEntry" + Integer.toString(i, 10))) 854 ).toMap 855 ) ++ ( 856 (0 until l1plusPrefetcherParameters.nEntries).map(i => 857 ("L1+PrefetchPenalty" + Integer.toString(i, 10), (0x1042 + dcacheParameters.nMissEntries + icacheParameters.nMissEntries + i, "perfCntL1plusPrefetchPenaltyEntry" + Integer.toString(i, 10))) 858 ).toMap 859 ) ++ ( 860 (0 until l2PrefetcherParameters.nEntries).map(i => 861 ("L2PrefetchPenalty" + Integer.toString(i, 10), (0x1042 + dcacheParameters.nMissEntries + icacheParameters.nMissEntries + l1plusPrefetcherParameters.nEntries + i, "perfCntL2PrefetchPenaltyEntry" + Integer.toString(i, 10))) 862 ).toMap 863 ) 864 865 emuPerfCntList.foreach { 866 case (_, (address, boringId)) => 867 if (hasEmuPerfCnt) { 868 ExcitingUtils.addSink(emuPerfCntCond(address & 0x7f), boringId, ConnectionType.Perf) 869 } 870 // if (!hasEmuPerfCnt) { 871 // // do not enable perfcnts except for Mcycle and Minstret 872 // if (address != emuPerfCntList("Mcycle")._1 && address != emuPerfCntList("Minstret")._1) { 873 // perfCntCond(address & 0x7f) := false.B 874 // } 875 // } 876 } 877 878 val xstrap = WireInit(false.B) 879 if (!env.FPGAPlatform && EnableBPU) { 880 ExcitingUtils.addSink(xstrap, "XSTRAP", ConnectionType.Debug) 881 } 882 def readWithScala(addr: Int): UInt = mapping(addr)._1 883 884 val difftestIntrNO = Mux(raiseIntr, causeNO, 0.U) 885 886 if (!env.FPGAPlatform) { 887 888 // display all perfcnt when nooptrap is executed 889 when (xstrap) { 890 printf("======== PerfCnt =========\n") 891 emuPerfCntList.toSeq.sortBy(_._2._1).foreach { case (str, (address, _)) => 892 printf("%d <- " + str + "\n", readWithScala(address)) 893 } 894 } 895 896 ExcitingUtils.addSource(difftestIntrNO, "difftestIntrNOfromCSR") 897 ExcitingUtils.addSource(causeNO, "difftestCausefromCSR") 898 ExcitingUtils.addSource(priviledgeMode, "difftestMode", Debug) 899 ExcitingUtils.addSource(mstatus, "difftestMstatus", Debug) 900 ExcitingUtils.addSource(mstatus & sstatusRmask, "difftestSstatus", Debug) 901 ExcitingUtils.addSource(mepc, "difftestMepc", Debug) 902 ExcitingUtils.addSource(sepc, "difftestSepc", Debug) 903 ExcitingUtils.addSource(mtval, "difftestMtval", Debug) 904 ExcitingUtils.addSource(stval, "difftestStval", Debug) 905 ExcitingUtils.addSource(mtvec, "difftestMtvec", Debug) 906 ExcitingUtils.addSource(stvec, "difftestStvec", Debug) 907 ExcitingUtils.addSource(mcause, "difftestMcause", Debug) 908 ExcitingUtils.addSource(scause, "difftestScause", Debug) 909 ExcitingUtils.addSource(satp, "difftestSatp", Debug) 910 ExcitingUtils.addSource(mipReg, "difftestMip", Debug) 911 ExcitingUtils.addSource(mie, "difftestMie", Debug) 912 ExcitingUtils.addSource(mscratch, "difftestMscratch", Debug) 913 ExcitingUtils.addSource(sscratch, "difftestSscratch", Debug) 914 ExcitingUtils.addSource(mideleg, "difftestMideleg", Debug) 915 ExcitingUtils.addSource(medeleg, "difftestMedeleg", Debug) 916 } 917 918 if (env.DualCoreDifftest) { 919 difftestIO.intrNO := RegNext(difftestIntrNO) 920 difftestIO.cause := RegNext(causeNO) 921 difftestIO.priviledgeMode := priviledgeMode 922 difftestIO.mstatus := mstatus 923 difftestIO.sstatus := mstatus & sstatusRmask 924 difftestIO.mepc := mepc 925 difftestIO.sepc := sepc 926 difftestIO.mtval:= mtval 927 difftestIO.stval:= stval 928 difftestIO.mtvec := mtvec 929 difftestIO.stvec := stvec 930 difftestIO.mcause := mcause 931 difftestIO.scause := scause 932 difftestIO.satp := satp 933 difftestIO.mip := mipReg 934 difftestIO.mie := mie 935 difftestIO.mscratch := mscratch 936 difftestIO.sscratch := sscratch 937 difftestIO.mideleg := mideleg 938 difftestIO.medeleg := medeleg 939 } 940} 941