From 150f4ac09ce84a386bd17c5663ad3389d38d47f1 Mon Sep 17 00:00:00 2001 From: Takehana Date: Sat, 3 Jun 2023 11:46:31 +0800 Subject: [PATCH 1/4] fix: adapt DCache maintenance to BRAM --- src/src/memory/DCache.scala | 284 ++++++++++++------------- src/src/memory/ICache.scala | 2 +- src/src/memory/enums/DCacheState.scala | 3 +- src/src/memory/enums/ICacheState.scala | 2 +- 4 files changed, 146 insertions(+), 145 deletions(-) diff --git a/src/src/memory/DCache.scala b/src/src/memory/DCache.scala index a8ce8bf8..ab20a872 100644 --- a/src/src/memory/DCache.scala +++ b/src/src/memory/DCache.scala @@ -183,39 +183,6 @@ class DCache( assert(isPow2(Param.Count.DCache.setLen)) val randomNum = LFSR(log2Ceil(Param.Count.DCache.setLen) + 1) - // Debug: Init cache -// if (isDebug) { -// val debugEnReg = RegNext(false.B, true.B) -// -// statusTagRams.zip(dataLineRams).foreach { -// case (tRam, dRam) => -// (tRam.io.debugPorts, dRam.io.debugPorts) match { -// case (Some(tPorts), Some(dPorts)) => -// tPorts.zip(dPorts).foreach { -// case (tPort, dPort) => -// tPort.en := false.B -// dPort.en := false.B -// } -// } -// case (_, _) => -// } -// debugAddrSeq.lazyZip(debugStatusTagSeq).lazyZip(debugDataLineSeq).lazyZip(debugSetNumSeq).zipWithIndex.foreach { -// case ((addr, st, dl, num), i) => -// (statusTagRams(num).io.debugPorts, dataLineRams(num).io.debugPorts) match { -// case (Some(tPorts), Some(dPorts)) => -// val tPort = tPorts(i) -// val dPort = dPorts(i) -// tPort.en := debugEnReg -// tPort.addr := addr -// tPort.data := st -// dPort.en := debugEnReg -// dPort.addr := addr -// dPort.data := dl -// } -// case (_, _) => -// } -// } - val stateReg = RegInit(State.ready) val nextState = WireDefault(stateReg) stateReg := nextState // Fallback: Keep state @@ -266,30 +233,24 @@ class DCache( } // Refill state regs - val isNeedWbReg = RegInit(false.B) - val isReadReqSentReg = RegInit(false.B) - val isWriteReqSentReg = RegInit(false.B) - isReadReqSentReg := isReadReqSentReg // Fallback: Keep data - isWriteReqSentReg := isWriteReqSentReg // Fallback: Keep data - isNeedWbReg := isNeedWbReg - - // Maintenance write info regs - val isMaintenanceInitWrite = RegNext(false.B, false.B) - val isMaintenanceHit = RegInit(false.B) - isMaintenanceHit := isMaintenanceHit + val isNeedWbReg = RegInit(false.B) + val isReadReqSentReg = RegInit(false.B) + val isWriteBackReqSentReg = RegInit(false.B) + isReadReqSentReg := isReadReqSentReg // Fallback: Keep data + isWriteBackReqSentReg := isWriteBackReqSentReg // Fallback: Keep data + isNeedWbReg := isNeedWbReg // Maintenance write-back info regs - val setCountDownReg = RegInit(0.U(log2Ceil(Param.Count.DCache.setLen).W)) - val isSetCountDownCompleteReg = RegInit(false.B) - val dataCountDownReg = RegInit(0.U(log2Ceil(Param.Count.DCache.dataPerLine).W)) - val isDataCountDownCompleteReg = RegInit(false.B) - setCountDownReg := setCountDownReg - isSetCountDownCompleteReg := isSetCountDownCompleteReg - dataCountDownReg := dataCountDownReg - isDataCountDownCompleteReg := isDataCountDownCompleteReg + val setCountDownReg = RegInit(0.U(log2Ceil(Param.Count.DCache.setLen).W)) + val dataCountDownReg = RegInit(0.U(log2Ceil(Param.Count.DCache.dataPerLine).W)) + setCountDownReg := setCountDownReg + dataCountDownReg := dataCountDownReg + + val isSetCountDownZero = WireDefault(setCountDownReg === 0.U) + val isDataCountDownComplete = WireDefault(dataCountDownReg === 0.U) def handleWb(addr: UInt, data: UInt): Unit = { - when(!isWriteReqSentReg) { + when(!isWriteBackReqSentReg) { // Stage 2.b/c.3, 3.1: Send write request axiMaster.io.write.req.isValid := true.B @@ -298,7 +259,7 @@ class DCache( when(axiMaster.io.write.req.isReady) { // Next Stage 2.b/c.4, 3.2 - isWriteReqSentReg := true.B + isWriteBackReqSentReg := true.B } }.otherwise { // Stage 2.b/c.4, 3.2: Wait for write complete @@ -441,8 +402,8 @@ class DCache( lastReg.setIndex := refillSetIndex // Init refill state regs - isReadReqSentReg := false.B - isWriteReqSentReg := false.B + isReadReqSentReg := false.B + isWriteBackReqSentReg := false.B switch(io.accessPort.req.client.rw) { is(ReadWriteSel.read) { @@ -458,20 +419,16 @@ class DCache( } // Maintenance + setCountDownReg := (Param.Count.DCache.setLen - 1).U + dataCountDownReg := (Param.Count.DCache.dataPerLine - 1).U + when(io.maintenancePort.client.isL1Valid) { - isMaintenanceHit := isCacheHit - isSetCountDownCompleteReg := false.B - isDataCountDownCompleteReg := false.B - setCountDownReg := (Param.Count.DCache.setLen - 1).U - dataCountDownReg := (Param.Count.DCache.dataPerLine - 1).U - isNeedWbReg := true.B - isWriteReqSentReg := false.B + isNeedWbReg := true.B + isWriteBackReqSentReg := false.B when(io.maintenancePort.client.isInit) { - isMaintenanceInitWrite := true.B - - // Next Stage 2.a* - nextState := State.write // TODO: Refactor this + // Next Stage: Maintenance for all sets (no write-back) + nextState := State.maintenanceInit } when(io.maintenancePort.client.isCoherentByIndex) { // Next Stage: Maintenance for all sets @@ -618,16 +575,66 @@ class DCache( handleWb(last.wbMemAddr, lastReg.dataLine.asUInt) - when(isWriteReqSentReg && axiMaster.io.write.res.isComplete) { + when(isWriteBackReqSentReg && axiMaster.io.write.res.isComplete) { // Next Stage 1 nextState := State.ready } } + is(State.maintenanceInit) { + // Maintenance: Init cache line + + val queryIndex = WireDefault(queryIndexFromMemAddr(lastReg.memAddr)) + + statusTagRams.foreach { ram => + ram.io.isWrite := true.B + ram.io.dataIn := 0.U + ram.io.addr := queryIndex + } + } + is(State.maintenanceHit) { + val queryIndex = WireDefault(queryIndexFromMemAddr(reqMemAddr)) + + // Step 2: Read status-tag + val statusTagLines = WireDefault(VecInit(statusTagRams.map(ram => toStatusTagLine(ram.io.dataOut)))) + + // Step 2: Read data request (for write-back) + dataLineRams.foreach { ram => + ram.io.addr := queryIndex + } + + // Step 2: Decode + val tag = WireDefault(tagFromMemAddr(reqMemAddr)) + + // Step 2: Calculate if hit and select + val isSelectedVec = WireDefault(VecInit(statusTagLines.map(line => line.isValid && (line.tag === tag)))) + val setIndex = WireDefault(OHToUInt(isSelectedVec)) + val isCacheHit = WireDefault(isSelectedVec.reduce(_ || _)) + + // Step 2: Save data for later use + lastReg.memAddr := reqMemAddr + lastReg.statusTagLines := statusTagLines + lastReg.setIndex := setIndex + + when(isCacheHit) { + // Next Stage: Coherent by hit + nextState := State.maintenanceOne + }.otherwise { + // Next Stage 1 + nextState := State.ready + } + } + + is(State.maintenanceOne) { // Maintenance: Coherent by hit val queryIndex = WireDefault(queryIndexFromMemAddr(lastReg.memAddr)) + + dataLineRams.foreach { ram => + ram.io.addr := queryIndex + } + val writeBackAddr = WireDefault( Cat( tagFromMemAddr(lastReg.memAddr), @@ -636,45 +643,38 @@ class DCache( 0.U(log2Ceil(wordLength / byteLength).W) ) ) - val dataLines = WireDefault(VecInit(dataLineRams.map(_.io.dataIn))) + val dataLines = WireDefault(VecInit(dataLineRams.map(_.io.dataIn))) // Delay for 1 cycle val selectedDataLine = WireDefault(dataLines(lastReg.setIndex)) dataLineRams.map(_.io.addr).foreach(_ := queryIndex) - when(isMaintenanceHit) { - when(last.selectedStatusTag.isDirty) { - when(isNeedWbReg) { - when(dataCountDownReg === 0.U) { - isDataCountDownCompleteReg := true.B + when(last.selectedStatusTag.isDirty) { + when(isNeedWbReg) { + handleWb(writeBackAddr, selectedDataLine(dataCountDownReg)) + }.otherwise { + when(isDataCountDownComplete) { + statusTagRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === lastReg.setIndex + ram.io.dataIn := 0.U + ram.io.addr := queryIndex } - handleWb(writeBackAddr, selectedDataLine(dataCountDownReg)) + + // Next Stage 1 + nextState := State.ready }.otherwise { - when(isDataCountDownCompleteReg) { - statusTagRams.zipWithIndex.foreach { - case (ram, index) => - ram.io.isWrite := index.U === lastReg.setIndex - ram.io.dataIn := 0.U - ram.io.addr := queryIndex - } - // Next Stage 1 - nextState := State.ready - }.otherwise { - dataCountDownReg := dataCountDownReg - 1.U - isNeedWbReg := true.B - } - } - }.otherwise { - statusTagRams.zipWithIndex.foreach { - case (ram, index) => - ram.io.isWrite := index.U === lastReg.setIndex - ram.io.dataIn := 0.U - ram.io.addr := queryIndex + dataCountDownReg := dataCountDownReg - 1.U + isNeedWbReg := true.B } - - // Next Stage 1 - nextState := State.ready } }.otherwise { + statusTagRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === lastReg.setIndex + ram.io.dataIn := 0.U + ram.io.addr := queryIndex + } + // Next Stage 1 nextState := State.ready } @@ -683,68 +683,68 @@ class DCache( is(State.maintenanceAll) { // Maintenance: Coherent by index - val queryIndex = WireDefault(queryIndexFromMemAddr(lastReg.memAddr)) + reqMemAddr := reqMemAddr + + val queryIndex = WireDefault(queryIndexFromMemAddr(reqMemAddr)) val writeBackAddr = WireDefault( Cat( - tagFromMemAddr(lastReg.memAddr), + tagFromMemAddr(reqMemAddr), queryIndex, dataCountDownReg, 0.U(log2Ceil(wordLength / byteLength).W) ) ) - val dataLines = WireDefault(VecInit(dataLineRams.map(_.io.dataOut))) + val dataLines = WireDefault(VecInit(dataLineRams.map(_.io.dataOut))) // Delay for 1 cycle val selectedDataLine = WireDefault(dataLines(setCountDownReg)) val statusTagLines = WireDefault(VecInit(statusTagRams.map(ram => toStatusTagLine(ram.io.dataOut)))) dataLineRams.map(_.io.addr).foreach(_ := queryIndex) - statusTagRams.map(_.io.addr).foreach(_ := queryIndex) - when(isSetCountDownCompleteReg) { - // Next Stage 1 - nextState := State.ready - }.otherwise { - when(statusTagLines(setCountDownReg).isDirty) { - when(isNeedWbReg) { - when(dataCountDownReg === 0.U) { - isDataCountDownCompleteReg := true.B + when(statusTagLines(setCountDownReg).isDirty) { + when(isNeedWbReg) { + handleWb(writeBackAddr, selectedDataLine(dataCountDownReg)) + }.otherwise { + when(isDataCountDownComplete) { + when(!isSetCountDownZero) { + setCountDownReg := setCountDownReg - 1.U } - handleWb(writeBackAddr, selectedDataLine(dataCountDownReg)) - }.otherwise { - when(isDataCountDownCompleteReg) { - statusTagRams.zipWithIndex.foreach { - case (ram, index) => - ram.io.isWrite := index.U === setCountDownReg - ram.io.dataIn := 0.U - ram.io.addr := queryIndex - } - when(setCountDownReg === 0.U) { - isSetCountDownCompleteReg := true.B - }.otherwise { - setCountDownReg := setCountDownReg - 1.U - } - dataCountDownReg := (Param.Count.DCache.dataPerLine - 1).U - isNeedWbReg := true.B - }.otherwise { - dataCountDownReg := dataCountDownReg - 1.U - isNeedWbReg := true.B + statusTagRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === setCountDownReg + ram.io.dataIn := 0.U + ram.io.addr := queryIndex } - } - }.otherwise { - statusTagRams.zipWithIndex.foreach { - case (ram, index) => - ram.io.isWrite := index.U === setCountDownReg - ram.io.dataIn := 0.U - ram.io.addr := queryIndex - } - when(setCountDownReg === 0.U) { - isSetCountDownCompleteReg := true.B + dataCountDownReg := (Param.Count.DCache.dataPerLine - 1).U + + when(isSetCountDownZero) { + // Next Stage 1 + nextState := State.ready + }.otherwise { + isNeedWbReg := true.B + } }.otherwise { - setCountDownReg := setCountDownReg - 1.U + dataCountDownReg := dataCountDownReg - 1.U + isNeedWbReg := true.B } - dataCountDownReg := (Param.Count.DCache.dataPerLine - 1).U - isNeedWbReg := true.B + } + }.otherwise { + statusTagRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === setCountDownReg + ram.io.dataIn := 0.U + ram.io.addr := queryIndex + } + + dataCountDownReg := (Param.Count.DCache.dataPerLine - 1).U + + when(isSetCountDownZero) { + // Next Stage 1 + nextState := State.ready + }.otherwise { + setCountDownReg := setCountDownReg - 1.U + isNeedWbReg := true.B } } } diff --git a/src/src/memory/ICache.scala b/src/src/memory/ICache.scala index 9ac69830..9120d101 100644 --- a/src/src/memory/ICache.scala +++ b/src/src/memory/ICache.scala @@ -299,7 +299,7 @@ class ICache( isMaintenanceHit := isCacheHit when(io.maintenancePort.client.isInit) { - // Next Stage: Write for maintenance init + // Next Stage: Maintenance for all sets nextState := State.maintenanceAll } when(io.maintenancePort.client.isCoherentByIndex) { diff --git a/src/src/memory/enums/DCacheState.scala b/src/src/memory/enums/DCacheState.scala index 6bff1ed2..4d18dcaf 100644 --- a/src/src/memory/enums/DCacheState.scala +++ b/src/src/memory/enums/DCacheState.scala @@ -3,5 +3,6 @@ package memory.enums import chisel3.ChiselEnum object DCacheState extends ChiselEnum { - val ready, write, refillForRead, refillForWrite, onlyWb, maintenanceHit, maintenanceAll = Value + val ready, refillForRead, refillForWrite, onlyWb, maintenanceInit, maintenanceHit, maintenanceOne, maintenanceAll = + Value } diff --git a/src/src/memory/enums/ICacheState.scala b/src/src/memory/enums/ICacheState.scala index 1ccfd4d5..77ac8c98 100644 --- a/src/src/memory/enums/ICacheState.scala +++ b/src/src/memory/enums/ICacheState.scala @@ -3,5 +3,5 @@ package memory.enums import chisel3.ChiselEnum object ICacheState extends ChiselEnum { - val ready, refillForRead, maintenanceInit, maintenanceAll, maintenanceHit = Value + val ready, refillForRead, maintenanceAll, maintenanceHit = Value } From bfa588f3b9f19dfba59bef8a36409707fef88eb5 Mon Sep 17 00:00:00 2001 From: Takehana Date: Sat, 3 Jun 2023 11:47:36 +0800 Subject: [PATCH 2/4] fix: no init for BRAM --- src/src/memory/BRam.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/memory/BRam.scala b/src/src/memory/BRam.scala index 3c2fb51e..4ae714e9 100644 --- a/src/src/memory/BRam.scala +++ b/src/src/memory/BRam.scala @@ -15,7 +15,7 @@ class BRam(size: Int, dataWidth: Int) extends Module { val dataOut = Output(UInt(dataWidth.W)) }) - val data = RegInit(VecInit(Seq.fill(size)(0.U(dataWidth.W)))) + val data = Reg(Vec(size, UInt(dataWidth.W))) // Read io.dataOut := RegNext(data(io.addr)) From fe9fb9c519f13431800455cd2b463fa803624c27 Mon Sep 17 00:00:00 2001 From: Takehana Date: Sat, 3 Jun 2023 12:08:48 +0800 Subject: [PATCH 3/4] refactor!: migrate ICache to BRAM --- src/src/memory/DCache.scala | 2 - src/src/memory/ICache.scala | 224 ++++++++++++------------- src/src/memory/enums/ICacheState.scala | 2 +- 3 files changed, 110 insertions(+), 118 deletions(-) diff --git a/src/src/memory/DCache.scala b/src/src/memory/DCache.scala index ab20a872..b74f2925 100644 --- a/src/src/memory/DCache.scala +++ b/src/src/memory/DCache.scala @@ -23,8 +23,6 @@ class DCache( val axiMasterPort = new AxiMasterInterface }) - // TODO: Maintenance is not tailored for BRAM - // Read cache hit diagram: // clock: ^_____________________________^___________________ // isReady = T isReady = T diff --git a/src/src/memory/ICache.scala b/src/src/memory/ICache.scala index 9120d101..dd37bbb5 100644 --- a/src/src/memory/ICache.scala +++ b/src/src/memory/ICache.scala @@ -24,12 +24,6 @@ class ICache( val axiMasterPort = new AxiMasterInterface }) - // TODO: Remove DontCare - io <> DontCare - - // TODO: Remove debug - val debugDataIndex = WireDefault(0.U(8.W)) - // Read cache hit diagram: // clock: ^_____________________________^___________________ // isReady = T isReady = T @@ -101,11 +95,9 @@ class ICache( // RAMs for valid and tag val statusTagRams = Seq.fill(Param.Count.ICache.setLen)( Module( - new SimpleRam( + new BRam( Param.Count.ICache.sizePerRam, - ICacheStatusTagBundle.width, - isDebug, - debugWriteNum + ICacheStatusTagBundle.width ) ) ) @@ -113,18 +105,16 @@ class ICache( // RAMs for data line val dataLineRams = Seq.fill(Param.Count.ICache.setLen)( Module( - new SimpleRam( + new BRam( Param.Count.ICache.sizePerRam, - Param.Width.ICache._dataLine, - isDebug, - debugWriteNum + Param.Width.ICache._dataLine ) ) ) (statusTagRams ++ dataLineRams).foreach { ram => - ram.io := DontCare - ram.io.writePort.en := false.B // Fallback: Not write + ram.io := DontCare + ram.io.isWrite := false.B // Fallback: Not write } // AXI master @@ -144,37 +134,6 @@ class ICache( assert(isPow2(Param.Count.ICache.setLen)) val randomNum = LFSR(log2Ceil(Param.Count.ICache.setLen) + 1) - // Debug: Init cache - if (isDebug) { - val debugEnReg = RegNext(false.B, true.B) - - statusTagRams.zip(dataLineRams).foreach { - case (tRam, dRam) => - (tRam.io.debugPorts, dRam.io.debugPorts) match { - case (Some(tPorts), Some(dPorts)) => - tPorts.zip(dPorts).foreach { - case (tPort, dPort) => - tPort.en := false.B - dPort.en := false.B - } - } - } - debugAddrSeq.lazyZip(debugStatusTagSeq).lazyZip(debugDataLineSeq).lazyZip(debugSetNumSeq).zipWithIndex.foreach { - case ((addr, st, dl, num), i) => - (statusTagRams(num).io.debugPorts, dataLineRams(num).io.debugPorts) match { - case (Some(tPorts), Some(dPorts)) => - val tPort = tPorts(i) - val dPort = dPorts(i) - tPort.en := debugEnReg - tPort.addr := addr - tPort.data := st - dPort.en := debugEnReg - dPort.addr := addr - dPort.data := dl - } - } - } - val stateReg = RegInit(State.ready) val nextState = WireDefault(stateReg) stateReg := nextState // Fallback: Keep state @@ -185,13 +144,20 @@ class ICache( io.accessPort.res.isFailed := false.B // Fallback: Not failed - val isReadValidReg = RegNext(false.B, false.B) // Fallback: Not valid - val isReadFailedReg = RegNext(false.B, false.B) // Fallback: Not failed - io.accessPort.res.isComplete := isReadValidReg + io.accessPort.res.isComplete := false.B // Falback: Not complete + + io.accessPort.res.read.data := DontCare + + val currentMemAddr = WireDefault( + Mux( + io.maintenancePort.client.isL1Valid, + io.maintenancePort.client.addr, + io.accessPort.req.client.addr + ) + ) - val readDataReg = RegInit(0.U(Width.Mem.data)) - readDataReg := readDataReg // Fallback: Keep data - io.accessPort.res.read.data := readDataReg + val isHasReqReg = RegNext(false.B, false.B) // Fallback: Not valid + val reqMemAddr = RegNext(currentMemAddr) // Fallback: Current memory access address // Keep request and cache query information val lastReg = Reg(new Bundle { @@ -206,69 +172,66 @@ class ICache( val isReadReqSentReg = RegInit(false.B) isReadReqSentReg := isReadReqSentReg // Fallback: Keep data - // Maintenance write info regs - val isMaintenanceHit = RegInit(false.B) - isMaintenanceHit := isMaintenanceHit - switch(stateReg) { // Note: Can accept request when in the second cycle of write (hit), // as long as the write information is passed to cache query is(State.ready) { - io.accessPort.req.isReady := !io.maintenancePort.client.isL1Valid // TODO: Adapt L2 cache - io.maintenancePort.isReady := true.B - - // Stage 1 and Stage 2.a: Cache query + // Stage 1 and Stage 2.a: Read BRAM and cache query in two cycles - // Decode - val memAddr = WireDefault( - Mux( - io.maintenancePort.client.isL1Valid, - io.maintenancePort.client.addr, - io.accessPort.req.client.addr - ) - ) - val tag = WireDefault(tagFromMemAddr(memAddr)) - val queryIndex = WireDefault(queryIndexFromMemAddr(memAddr)) - val dataIndex = WireDefault(dataIndexFromMemAddr(memAddr)) + io.accessPort.req.isReady := !io.maintenancePort.client.isL1Valid // Fallback: Ready for request + io.maintenancePort.isReady := true.B - // Read status-tag + // Step 1: BRAM read request + val currentQueryIndex = WireDefault(queryIndexFromMemAddr(currentMemAddr)) statusTagRams.foreach { ram => - ram.io.readPort.addr := queryIndex + ram.io.addr := currentQueryIndex } - val statusTagLines = WireDefault(VecInit(statusTagRams.map(ram => toStatusTagLine(ram.io.readPort.data)))) - - // Read data (for read and write) dataLineRams.foreach { ram => - ram.io.readPort.addr := queryIndex + ram.io.addr := currentQueryIndex } - val dataLines = WireDefault(VecInit(dataLineRams.map(_.io.readPort.data))) + isHasReqReg := io.accessPort.req.client.isValid + + // Step 2: Read status-tag + val statusTagLines = WireDefault(VecInit(statusTagRams.map(ram => toStatusTagLine(ram.io.dataOut)))) + + // Step 2: Read data (for read and write) + val dataLines = WireDefault(VecInit(dataLineRams.map(_.io.dataOut))) - // Calculate if hit and select + // Step 2: Decode + val tag = WireDefault(tagFromMemAddr(reqMemAddr)) + val dataIndex = WireDefault(dataIndexFromMemAddr(reqMemAddr)) + + // Step 2: Calculate if hit and select val isSelectedVec = WireDefault(VecInit(statusTagLines.map(line => line.isValid && (line.tag === tag)))) val setIndex = WireDefault(OHToUInt(isSelectedVec)) val selectedDataLine = WireDefault(toDataLine(dataLines(setIndex))) val isCacheHit = WireDefault(isSelectedVec.reduce(_ || _)) - // Save data for later use - lastReg.memAddr := memAddr + // Step 2: Save data for later use + lastReg.memAddr := reqMemAddr lastReg.statusTagLines := statusTagLines lastReg.setIndex := setIndex lastReg.dataLine := selectedDataLine - // Select data by data index from byte offset + // Step 2: Select data by data index from byte offset val selectedData = WireDefault(selectedDataLine(dataIndex)) - when(io.accessPort.req.client.isValid) { + // Step 2: Whether hit or not + when(isHasReqReg) { when(isCacheHit) { // Cache hit - // Remember to use regs - isReadValidReg := true.B - readDataReg := selectedData + + // Step 2: Read result in same cycle output + io.accessPort.res.isComplete := true.B + io.accessPort.res.read.data := selectedData // Next Stage 1 nextState := State.ready }.otherwise { // Cache miss + io.accessPort.req.isReady := false.B + io.maintenancePort.isReady := false.B + // Select a set to refill // First, select from invalid, if it can @@ -296,8 +259,6 @@ class ICache( // Maintenance when(io.maintenancePort.client.isL1Valid) { - isMaintenanceHit := isCacheHit - when(io.maintenancePort.client.isInit) { // Next Stage: Maintenance for all sets nextState := State.maintenanceAll @@ -339,25 +300,24 @@ class ICache( statusTag.tag := tagFromMemAddr(lastReg.memAddr) // Write status-tag to RAM - statusTagRams.map(_.io.writePort).zipWithIndex.foreach { - case (writePort, index) => - writePort.en := index.U === lastReg.setIndex - writePort.data := statusTag.asUInt - writePort.addr := queryIndex + statusTagRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === lastReg.setIndex + ram.io.dataIn := statusTag.asUInt + ram.io.addr := queryIndex } // Write to data line RAM - dataLineRams.map(_.io.writePort).zipWithIndex.foreach { - case (writePort, index) => - writePort.en := index.U === lastReg.setIndex - writePort.data := axiMaster.io.read.res.data - writePort.addr := queryIndex + dataLineRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === lastReg.setIndex + ram.io.dataIn := axiMaster.io.read.res.data + ram.io.addr := queryIndex } // Return read data - debugDataIndex := dataIndexFromMemAddr(lastReg.memAddr) val dataLine = WireDefault(toDataLine(axiMaster.io.read.res.data)) - val readData = WireDefault(dataLine(debugDataIndex)) + val readData = WireDefault(dataLine(dataIndexFromMemAddr(lastReg.memAddr))) // TODO: Add one more cycle for return read data io.accessPort.res.isComplete := true.B io.accessPort.res.isFailed := axiMaster.io.read.res.isFailed @@ -370,33 +330,67 @@ class ICache( } is(State.maintenanceHit) { - // Maintenance: Coherent by hit + val queryIndex = WireDefault(queryIndexFromMemAddr(reqMemAddr)) - val queryIndex = WireDefault(queryIndexFromMemAddr(lastReg.memAddr)) + // Step 2: Read status-tag + val statusTagLines = WireDefault(VecInit(statusTagRams.map(ram => toStatusTagLine(ram.io.dataOut)))) - when(isMaintenanceHit) { - statusTagRams.map(_.io.writePort).zipWithIndex.foreach { - case (writePort, index) => - writePort.en := index.U === lastReg.setIndex - writePort.data := 0.U - writePort.addr := queryIndex - } + // Step 2: Read data request (for write-back) + dataLineRams.foreach { ram => + ram.io.addr := queryIndex + } + + // Step 2: Decode + val tag = WireDefault(tagFromMemAddr(reqMemAddr)) + + // Step 2: Calculate if hit and select + val isSelectedVec = WireDefault(VecInit(statusTagLines.map(line => line.isValid && (line.tag === tag)))) + val setIndex = WireDefault(OHToUInt(isSelectedVec)) + val isCacheHit = WireDefault(isSelectedVec.reduce(_ || _)) + + // Step 2: Save data for later use + lastReg.memAddr := reqMemAddr + lastReg.statusTagLines := statusTagLines + lastReg.setIndex := setIndex + when(isCacheHit) { + // Next Stage: Coherent by hit + nextState := State.maintenanceOne + }.otherwise { // Next Stage 1 nextState := State.ready } } + is(State.maintenanceOne) { + // Maintenance: Coherent by hit + + val queryIndex = WireDefault(queryIndexFromMemAddr(lastReg.memAddr)) + + statusTagRams.zipWithIndex.foreach { + case (ram, index) => + ram.io.isWrite := index.U === lastReg.setIndex + ram.io.dataIn := 0.U + ram.io.addr := queryIndex + } + + // Next Stage 1 + nextState := State.ready + } + is(State.maintenanceAll) { // Maintenance: Coherent by index - val queryIndex = WireDefault(queryIndexFromMemAddr(lastReg.memAddr)) + val queryIndex = WireDefault(queryIndexFromMemAddr(reqMemAddr)) - statusTagRams.map(_.io.writePort).foreach { writePort => - writePort.en := true.B - writePort.data := 0.U - writePort.addr := queryIndex + statusTagRams.foreach { ram => + ram.io.isWrite := true.B + ram.io.dataIn := 0.U + ram.io.addr := queryIndex } + + // Next Stage 1 + nextState := State.ready } } } diff --git a/src/src/memory/enums/ICacheState.scala b/src/src/memory/enums/ICacheState.scala index 77ac8c98..2f9e2324 100644 --- a/src/src/memory/enums/ICacheState.scala +++ b/src/src/memory/enums/ICacheState.scala @@ -3,5 +3,5 @@ package memory.enums import chisel3.ChiselEnum object ICacheState extends ChiselEnum { - val ready, refillForRead, maintenanceAll, maintenanceHit = Value + val ready, refillForRead, maintenanceAll, maintenanceHit, maintenanceOne = Value } From 764b54ad984352e4cd6919800d498a19bcce9b8a Mon Sep 17 00:00:00 2001 From: Takehana Date: Sat, 3 Jun 2023 12:24:25 +0800 Subject: [PATCH 4/4] feat: add self-hosted CI --- .github/workflows/difftest-selfhost.yml | 55 +++++++++++++++++++++++++ .scalafmt.conf | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/difftest-selfhost.yml diff --git a/.github/workflows/difftest-selfhost.yml b/.github/workflows/difftest-selfhost.yml new file mode 100644 index 00000000..29974f57 --- /dev/null +++ b/.github/workflows/difftest-selfhost.yml @@ -0,0 +1,55 @@ +name: Self-hosted Difftest + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + difftest: + runs-on: self-hosted + + steps: + - uses: actions/checkout@v3 + + - name: Clone Chiplab Repo + uses: actions/checkout@v3 + with: + repository: Invalid-Syntax-NSCSCC/min-chiplab + token: ${{ secrets.DIFFTEST_ACCESS_TOKEN }} + path: chiplab + + - name: Prepare Environment + run: | + echo "`pwd`/chiplab/toolchains/loongarch32r-linux-gnusf-2022-05-20/bin" >> $GITHUB_PATH + + - name: Use Cache + uses: coursier/cache-action@v6 + + - name: Elaborate CPU + run: make + + - name: Move to Chiplab + run: | + export CHIPLAB_HOME=`pwd`/chiplab + make chiplab + + - name: Test + run: | + export CHIPLAB_HOME=`pwd`/chiplab + ./chiplab/sims/verilator/run_prog/configure.sh --run func/func_lab8 --tail-waveform --tail-simu-trace --waveform-tail-size 200 --trace-tail-size 200 + cd ./chiplab/sims/verilator/run_prog + make -j`nproc` > make_log.txt 2>&1 + sed -i '/RUN simulation/,$!d' make_log.txt + cat make_log.txt + + - name: Upload Result + uses: actions/upload-artifact@v3 + with: + name: difftest-log + path: | + ./chiplab/sims/verilator/run_prog/make_log.txt + ./chiplab/sims/verilator/run_prog/log/**/simu_trace.* + ./chiplab/sims/verilator/run_prog/obj/**/obj/test.s diff --git a/.scalafmt.conf b/.scalafmt.conf index 75dc9737..f2c06eb8 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -43,4 +43,4 @@ verticalMultiline.atDefnSite = true optIn.annotationNewlines = true -rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix] \ No newline at end of file +rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix]