From 3bd44c68416cc47935a32145277864fa80863ac7 Mon Sep 17 00:00:00 2001 From: LoveLonelyTime <1390751361@qq.com> Date: Mon, 5 Feb 2024 23:24:43 +0800 Subject: [PATCH] add timer --- src/main/scala/lltriscv/core/Core.scala | 17 ++++ .../scala/lltriscv/core/debug/Debug.scala | 7 ++ .../scala/lltriscv/core/execute/Memory.scala | 6 +- .../scala/lltriscv/core/record/CSRs.scala | 25 ++++-- .../core/retire/InstructionRetire.scala | 42 +++++---- .../lltriscv/peripheral/MachineTimer.scala | 86 +++++++++++++++++++ src/test/scala/lltriscv/test/NormalTest.scala | 17 +++- 7 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 src/main/scala/lltriscv/core/debug/Debug.scala create mode 100644 src/main/scala/lltriscv/peripheral/MachineTimer.scala diff --git a/src/main/scala/lltriscv/core/Core.scala b/src/main/scala/lltriscv/core/Core.scala index 0eeea7d..fc3bc53 100644 --- a/src/main/scala/lltriscv/core/Core.scala +++ b/src/main/scala/lltriscv/core/Core.scala @@ -47,6 +47,7 @@ import lltriscv.bus.AXIMaster import lltriscv.cache.CacheLineRequest2SMA import lltriscv.bus.AXIMasterIO import lltriscv.interconnect.SkipCacheSMAReaderInterconnect +import lltriscv.core.debug.DebugIO /* * LLT RISC-V Core Exquisite integration @@ -100,6 +101,11 @@ object CoreConfig { class LLTRISCVCoreExq(config: CoreConfig) extends Module { val io = IO(new Bundle { val axi = new AXIMasterIO() + + val mtime = Input(UInt(64.W)) + val mtimeIRQ = Input(Bool()) + + val debug = new DebugIO() }) private val coreFrontend = Module(new CoreFrontend(config)) @@ -148,6 +154,9 @@ class LLTRISCVCoreExq(config: CoreConfig) extends Module { coreBackend.io.updateLoadReservation <> coreExecute.io.updateLoadReservation coreBackend.io.predictorUpdate <> coreFrontend.io.predictorUpdate coreBackend.io.store <> coreExecute.io.retire + coreBackend.io.mtime := io.mtime + coreBackend.io.mtimeIRQ := io.mtimeIRQ + coreBackend.io.debug <> io.debug // TLBFlusher tlbFlusher.io.out1 <> coreFrontend.io.iTLBFlush @@ -401,6 +410,11 @@ class CoreBackend(config: CoreConfig) extends Module { val tlbFlush = new FlushCacheIO() val updateLoadReservation = new LoadReservationUpdateIO() + + val mtime = Input(UInt(64.W)) + val mtimeIRQ = Input(Bool()) + + val debug = new DebugIO() }) private val broadcaster = Module(new RoundRobinBroadcaster(config.executeQueueWidth)) private val instructionRetire = Module(new InstructionRetire(config.robDepth)) @@ -427,6 +441,7 @@ class CoreBackend(config: CoreConfig) extends Module { instructionRetire.io.iCacheFlush <> io.iCacheFlush instructionRetire.io.dCacheFlush <> io.dCacheFlush instructionRetire.io.tlbFlush <> io.tlbFlush + instructionRetire.io.debug <> io.debug instructionRetire.io.l2DCacheFlush.empty := true.B @@ -440,4 +455,6 @@ class CoreBackend(config: CoreConfig) extends Module { io.privilege := csr.io.privilege io.mstatus := csr.io.mstatus io.satp := csr.io.satp + csr.io.mtime := io.mtime + csr.io.mtimeIRQ := io.mtimeIRQ } diff --git a/src/main/scala/lltriscv/core/debug/Debug.scala b/src/main/scala/lltriscv/core/debug/Debug.scala new file mode 100644 index 0000000..fbce033 --- /dev/null +++ b/src/main/scala/lltriscv/core/debug/Debug.scala @@ -0,0 +1,7 @@ +package lltriscv.core.debug + +import chisel3._ + +class DebugIO extends Bundle { + val hit = Output(Bool()) +} diff --git a/src/main/scala/lltriscv/core/execute/Memory.scala b/src/main/scala/lltriscv/core/execute/Memory.scala index e360351..586cc2d 100644 --- a/src/main/scala/lltriscv/core/execute/Memory.scala +++ b/src/main/scala/lltriscv/core/execute/Memory.scala @@ -441,7 +441,11 @@ class MemoryReadWriteStage extends Module { } // Alloc ID - when(inReg.op in MemoryOperationType.writeValues) { + when(inReg.op === MemoryOperationType.sc) { // Advance judgment + when(scSuccess(inReg.vaddress)) { + io.out.bits.resultMemory(allocID) + } + }.elsewhen(inReg.op in MemoryOperationType.writeValues) { io.out.bits.resultMemory(allocID) } diff --git a/src/main/scala/lltriscv/core/record/CSRs.scala b/src/main/scala/lltriscv/core/record/CSRs.scala index affd04c..24c5666 100644 --- a/src/main/scala/lltriscv/core/record/CSRs.scala +++ b/src/main/scala/lltriscv/core/record/CSRs.scala @@ -35,15 +35,18 @@ class CSRs extends Module { val satp = Output(DataType.operation) val monitor = Flipped(new MonitorIO()) + + val mtime = Input(UInt(64.W)) + val mtimeIRQ = Input(Bool()) }) // Registers private val coreRegister = new CoreRegister() private val statusReg = new StatusRegister() private val exceptionReg = new ExceptionRegister() - private val interruptsReg = new InterruptsRegister(false.B, false.B, false.B, false.B) + private val interruptsReg = new InterruptsRegister(io.mtimeIRQ, false.B, false.B, false.B) private val virtualReg = new VirtualRegister(statusReg.mstatus.value(20), statusReg.privilege) - private val monitorRegister = new MonitorRegister(statusReg.privilege, io.monitor.instret) + private val monitorRegister = new MonitorRegister(statusReg.privilege, io.monitor.instret, io.mtime) // Fixed output io.satp := virtualReg.satp.value @@ -54,9 +57,12 @@ class CSRs extends Module { private val csrMappingTable = Seq( // Unprivileged "hc00".U -> monitorRegister.cycle, + "hc01".U -> monitorRegister.time, "hc02".U -> monitorRegister.instret, "hc80".U -> monitorRegister.cycleh, + "hc81".U -> monitorRegister.timeh, "hc82".U -> monitorRegister.instreth, + // S-Level "h100".U -> statusReg.sstatus, "h104".U -> interruptsReg.sie, @@ -183,6 +189,7 @@ class CSRs extends Module { when(io.trap.interruptTrigger) { val delegation = interruptsReg.mideleg.value(pendingInterruptCode) + printf("Pending code = %d\n", pendingInterruptCode) when(!delegation) { // M-Handler io.trap.handlerPC := exceptionReg.interruptMLevel(io.trap.trapPC, pendingInterruptCode, io.trap.trapVal) statusReg.trapToMLevel() @@ -517,7 +524,7 @@ class CoreRegister { } // TODO: mtime -class MonitorRegister(privilege: PrivilegeType.Type, instretVal: UInt) { +class MonitorRegister(privilege: PrivilegeType.Type, instretVal: UInt, mtime: UInt) { private val mcountinhibitReg = RegInit(DataType.operation.zeroAsUInt) private val mcounterenReg = RegInit(DataType.operation.zeroAsUInt) private val scounterenReg = RegInit(DataType.operation.zeroAsUInt) @@ -546,9 +553,13 @@ class MonitorRegister(privilege: PrivilegeType.Type, instretVal: UInt) { (privilege === PrivilegeType.S && !mcounterenReg(bit)) || (privilege === PrivilegeType.U && (!mcounterenReg(bit) || !scounterenReg(bit))) - val cycle = ReadAndWriteRegister(() => cycleCounter(31, 0), data => cycleCounter := cycleCounter(63, 32) ## data, () => guard(0)) - val cycleh = ReadAndWriteRegister(() => cycleCounter(63, 32), data => cycleCounter := data ## cycleCounter(31, 0), () => guard(0)) + // Read-only + val cycle = ReadAndWriteRegister(() => cycleCounter(31, 0), _ => (), () => guard(0)) + val cycleh = ReadAndWriteRegister(() => cycleCounter(63, 32), _ => (), () => guard(0)) + + val instret = ReadAndWriteRegister(() => instretCounter(31, 0), _ => (), () => guard(2)) + val instreth = ReadAndWriteRegister(() => instretCounter(63, 32), _ => (), () => guard(2)) - val instret = ReadAndWriteRegister(() => instretCounter(31, 0), data => instretCounter := instretCounter(63, 32) ## data, () => guard(2)) - val instreth = ReadAndWriteRegister(() => instretCounter(63, 32), data => instretCounter := data ## instretCounter(31, 0), () => guard(2)) + val time = ReadAndWriteRegister(() => mtime(31, 0), _ => (), () => guard(0)) + val timeh = ReadAndWriteRegister(() => mtime(63, 32), _ => (), () => guard(0)) } diff --git a/src/main/scala/lltriscv/core/retire/InstructionRetire.scala b/src/main/scala/lltriscv/core/retire/InstructionRetire.scala index bfdef79..c789c44 100644 --- a/src/main/scala/lltriscv/core/retire/InstructionRetire.scala +++ b/src/main/scala/lltriscv/core/retire/InstructionRetire.scala @@ -20,6 +20,7 @@ import lltriscv.cache.FlushCacheIO import lltriscv.utils.CoreUtils._ import lltriscv.utils.ChiselUtils._ import lltriscv.core.record.MonitorIO +import lltriscv.core.debug.DebugIO /* * Instruction retire @@ -66,7 +67,12 @@ class InstructionRetire(depth: Int) extends Module { val l2DCacheFlush = new FlushCacheIO() val iCacheFlush = new FlushCacheIO() val tlbFlush = new FlushCacheIO() + + // Debug + val debug = new DebugIO() }) + private val debugBreakpoint = RegInit(false.B) + io.debug.hit := debugBreakpoint private object Status extends ChiselEnum { val retire, dCache, l2DCache, iCache, tlb = Value @@ -126,6 +132,7 @@ class InstructionRetire(depth: Int) extends Module { io.correctPC := io.trap.handlerPC io.retired.ready := true.B + when(entry.pc >= "h80400000".U) { printf("Exception!!!! pc = %x, cause = %d,to = %x\n", entry.pc, entry.executeResult.exceptionCode, io.trap.handlerPC) } @@ -148,14 +155,14 @@ class InstructionRetire(depth: Int) extends Module { io.retired.ready := true.B - // when(entry.pc >= "h80400000".U) { - // printf( - // "spec violate!!!: pc = %x, sepc = %x, real = %x\n", - // entry.pc, - // entry.spec, - // entry.executeResult.real - // ) - // } + when(debugBreakpoint) { + printf( + "spec violate!!!: pc = %x, sepc = %x, real = %x\n", + entry.pc, + entry.spec, + entry.executeResult.real + ) + } } private def gotoXRetPath(entry: ROBTableEntry) = { @@ -203,14 +210,17 @@ class InstructionRetire(depth: Int) extends Module { io.predictorUpdate.entries(id).address := retireEntries(id).executeResult.real } - // when(retireEntries(id).pc >= "h80400000".U) { - // printf( - // "retired instruction: pc = %x , r = %x, v = %d\n", - // retireEntries(id).pc, - // retireEntries(id).executeResult.result, - // retireEntries(id).valid - // ) - // } + when(retireEntries(id).pc === "hc0002a44".U) { + debugBreakpoint := true.B + } + when(debugBreakpoint) { + printf( + "retired instruction: pc = %x , r = %x, v = %d\n", + retireEntries(id).pc, + retireEntries(id).executeResult.result, + retireEntries(id).valid + ) + } } private def retireStoreQueue(id: Int) = { diff --git a/src/main/scala/lltriscv/peripheral/MachineTimer.scala b/src/main/scala/lltriscv/peripheral/MachineTimer.scala new file mode 100644 index 0000000..a7ea4a5 --- /dev/null +++ b/src/main/scala/lltriscv/peripheral/MachineTimer.scala @@ -0,0 +1,86 @@ +package lltriscv.peripheral + +import chisel3._ +import chisel3.util._ + +import lltriscv.bus.AXIMasterIO + +import lltriscv.utils.ChiselUtils._ +import lltriscv.utils.CoreUtils._ + +class MachineTimer(base: String) extends Module { + val io = IO(new Bundle { + val axi = Flipped(new AXIMasterIO()) + val irq = Output(Bool()) + val mtime = Output(UInt(64.W)) + }) + + private val mtimeReg = RegInit(0.U(64.W)) + mtimeReg := mtimeReg + 1.U + io.mtime := mtimeReg + + private val mtimecmpReg = RegInit(0.U(64.W)) + io.irq := mtimeReg >= mtimecmpReg + + io.axi <> new AXIMasterIO().zero + + // AXI logic + private val readAddressReg = RegInit(0.U(32.W)) + + when(io.axi.ARVALID) { + io.axi.ARREADY := true.B + readAddressReg := io.axi.ARADDR - base.U + } + + io.axi.RVALID := true.B + io.axi.RRESP := 0.U + + switch(readAddressReg) { + is("h4000".U) { // mtimecmpl + io.axi.RDATA := mtimecmpReg(31, 0) + } + is("h4004".U) { // mtimecmph + io.axi.RDATA := mtimecmpReg(63, 32) + } + is("hbff8".U) { // mtimel + io.axi.RDATA := mtimeReg(31, 0) + } + is("hbffc".U) { // mtimeh + io.axi.RDATA := mtimeReg(63, 32) + } + } + + private val writeAddressReg = RegInit(0.U(32.W)) + + when(io.axi.AWVALID) { + io.axi.AWREADY := true.B + writeAddressReg := io.axi.AWADDR - base.U + } + + when(io.axi.WVALID) { + io.axi.WREADY := true.B + val data = io.axi.WDATA + printf("Current time: %d\n", mtimeReg) + switch(writeAddressReg) { + is("h4000".U) { // mtimecmpl + mtimecmpReg := mtimecmpReg(63, 32) ## data + printf("MTIMER: set mtimecmp = %d\n", mtimecmpReg(63, 32) ## data) + } + is("h4004".U) { // mtimecmph + mtimecmpReg := data ## mtimecmpReg(31, 0) + printf("MTIMER: set mtimecmp = %d\n", data ## mtimecmpReg(31, 0)) + } + is("hbff8".U) { // mtimel + mtimeReg := mtimeReg(63, 32) ## data + printf("MTIMER: set mtime = %d\n", mtimeReg(63, 32) ## data) + } + is("hbffc".U) { // mtimeh + mtimeReg := data ## mtimeReg(31, 0) + printf("MTIMER: set mtime = %d\n", data ## mtimeReg(31, 0)) + } + } + } + + io.axi.BVALID := true.B + io.axi.BRESP := 0.U +} diff --git a/src/test/scala/lltriscv/test/NormalTest.scala b/src/test/scala/lltriscv/test/NormalTest.scala index c29b985..1c1e78f 100644 --- a/src/test/scala/lltriscv/test/NormalTest.scala +++ b/src/test/scala/lltriscv/test/NormalTest.scala @@ -23,6 +23,8 @@ import lltriscv.peripheral.VirtualWriteHost import lltriscv.peripheral.VirtualUART import lltriscv.peripheral.MemoryHole import lltriscv.peripheral.VirtualRAM +import lltriscv.peripheral.MachineTimer +import lltriscv.core.debug.DebugIO class NormalTest extends AnyFlatSpec with ChiselScalatestTester { // WriteVcdAnnotation @@ -40,6 +42,8 @@ class NormalTest extends AnyFlatSpec with ChiselScalatestTester { val dataOut = Output(UInt(8.W)) val send = Output(Bool()) + + val debug = new DebugIO() }) private val core = Module(new LLTRISCVCoreExq(config)) @@ -48,6 +52,7 @@ class NormalTest extends AnyFlatSpec with ChiselScalatestTester { new AXIInterconnect( Seq( "h00000000", // hole + "h2000000", // mtime "h10000000", // uart "h80000000", // ram "hffff0000" // rom @@ -56,6 +61,7 @@ class NormalTest extends AnyFlatSpec with ChiselScalatestTester { ) private val hole = Module(new MemoryHole()) private val uart = Module(new VirtualUART("h10000000")) + private val mtimer = Module(new MachineTimer("h2000000")) private val rom = Module(new ROM(32, "hffff0000", "boot.hex")) private val ram = Module(new VirtualRAM("h80000000")) @@ -69,11 +75,16 @@ class NormalTest extends AnyFlatSpec with ChiselScalatestTester { io.send := uart.io.send interconnect.io.slaves(0) <> hole.io.axi - interconnect.io.slaves(1) <> uart.io.axi - interconnect.io.slaves(2) <> ram.io.axi - interconnect.io.slaves(3) <> rom.io.axi + interconnect.io.slaves(1) <> mtimer.io.axi + interconnect.io.slaves(2) <> uart.io.axi + interconnect.io.slaves(3) <> ram.io.axi + interconnect.io.slaves(4) <> rom.io.axi + core.io.mtime := mtimer.io.mtime + core.io.mtimeIRQ := mtimer.io.irq core.io.axi <> interconnect.io.master + + core.io.debug <> io.debug } "Normal test" should "pass" in {