diff --git a/chisel/playground/src/axi/FIFO.scala b/chisel/playground/src/axi/FIFO.scala deleted file mode 100644 index e7921df..0000000 --- a/chisel/playground/src/axi/FIFO.scala +++ /dev/null @@ -1,119 +0,0 @@ -package cpu.axi - -import chisel3._ -import chisel3.util._ - -/** A simple FIFO buffer implemented using Chisel's built-in Queue module. - * - * @param dataWidth - * The width of the data to be stored in the buffer. - * @param buffDepth - * The depth of the buffer (i.e. the number of elements it can hold). - * @param addrWidth - * The width of the address used to access the buffer. - */ -class FifoBuffer( - val dataWidth: Int = 32, - val buffDepth: Int = 4, - val addrWidth: Int = 2, -) extends Module { - val io = IO(new Bundle { - val wen = Input(Bool()) // Write enable signal. - val ren = Input(Bool()) // Read enable signal. - val input = Input(UInt(dataWidth.W)) // Data to be written to the buffer. - val output = Output(UInt(dataWidth.W)) // Data read from the buffer. - val empty = Output(Bool()) // Output signal indicating whether the buffer is empty. - val full = Output(Bool()) // Output signal indicating whether the buffer is full. - }) - - // Instantiate a Queue module with the given data width and buffer depth. - val queue = Module(new Queue(UInt(dataWidth.W), buffDepth)) - - // Connect the input and output signals to the Queue module. - queue.io.enq.valid := io.wen - queue.io.enq.bits := io.input - io.full := queue.io.enq.ready === false.B - queue.io.deq.ready := io.ren - io.output := queue.io.deq.bits - io.empty := queue.io.count === 0.U -} - -/** A simple counter that keeps track of the number of elements in a FIFO buffer. - * - * @param buffDepth - * The depth of the buffer (i.e. the number of elements it can hold). - * @param addrWidth - * The width of the address used to access the buffer. - */ -class FifoCount( - val buffDepth: Int = 4, - val addrWidth: Int = 2, -) extends Module { - val io = IO(new Bundle { - val wen = Input(Bool()) - val ren = Input(Bool()) - val empty = Output(Bool()) - val full = Output(Bool()) - }) - - val count = RegInit(0.U(addrWidth.W)) - - io.empty := count === 0.U - io.full := count === buffDepth.U - - when(io.ren && !io.empty) { - count := count - 1.U - }.elsewhen(io.wen && !io.full) { - count := count + 1.U - } -} - -/** A FIFO buffer with a valid signal that checks if the output data is related to a specific value. - * - * @param dataWidth - * The width of the data to be stored in the buffer. - * @param buffDepth - * The depth of the buffer (i.e. the number of elements it can hold). - * @param addrWidth - * The width of the address used to access the buffer. - * @param relatedDataWidth - * The width of the related data used to check if the output data is related to a specific value. - */ -class FifoBufferValid( - val dataWidth: Int = 33, - val buffDepth: Int = 6, - val addrWidth: Int = 3, - val relatedDataWidth: Int = 32, -) extends Module { - val io = IO(new Bundle { - val wen = Input(Bool()) // Write enable signal. - val ren = Input(Bool()) // Read enable signal. - val empty = Output(Bool()) // Output signal indicating whether the buffer is empty. - val full = Output(Bool()) // Output signal indicating whether the buffer is full. - val related_1 = Output( - Bool(), - ) // Output signal indicating whether the output data is related to a specific value. - val input = Input(UInt(dataWidth.W)) // Data to be written to the buffer. - val output = Output(UInt(dataWidth.W)) // Data read from the buffer. - val related_data_1 = Input( - UInt(relatedDataWidth.W), - ) // Related data used to check if the output data is related to a specific value. - }) - - // Instantiate a Queue module with the given data width and buffer depth. - val queue = Module(new Queue(UInt(dataWidth.W), buffDepth)) - - // Connect the input and output signals to the Queue module. - queue.io.enq.valid := io.wen - queue.io.enq.bits := io.input - io.full := queue.io.count === buffDepth.U - io.empty := queue.io.count === 0.U - io.output := queue.io.deq.bits - - // Connect the ready signal to the read enable input. - queue.io.deq.ready := io.ren - - // Check if the output data is related to a specific value. - io.related_1 := queue.io.deq.valid && io.related_data_1 === queue.io.deq - .bits(relatedDataWidth - 1, 0) -} \ No newline at end of file diff --git a/chisel/playground/src/cache/Cache.scala b/chisel/playground/src/cache/Cache.scala deleted file mode 100644 index e0df71a..0000000 --- a/chisel/playground/src/cache/Cache.scala +++ /dev/null @@ -1,30 +0,0 @@ -package cache - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ -import cpu.CpuConfig -import cpu.CacheConfig - -class Cache(implicit cpuConfig: CpuConfig) extends Module { - val io = IO(new Bundle { - val inst = Flipped(new Cache_ICache()) - val data = Flipped(new Cache_DCache()) - val axi = new AXI() - }) - - implicit val iCacheConfig = CacheConfig(cacheType = "icache") - implicit val dCacheConfig = CacheConfig(cacheType = "dcache") - - val icache = Module(new ICache(iCacheConfig)) - val dcache = Module(new DCache(dCacheConfig)) - val axi_interface = Module(new CacheAXIInterface()) - - icache.io.axi <> axi_interface.io.icache - dcache.io.axi <> axi_interface.io.dcache - - io.inst <> icache.io.cpu - io.data <> dcache.io.cpu - io.axi <> axi_interface.io.axi -} diff --git a/chisel/playground/src/cache/CacheAXIInterface.scala b/chisel/playground/src/cache/CacheAXIInterface.scala deleted file mode 100644 index 143613f..0000000 --- a/chisel/playground/src/cache/CacheAXIInterface.scala +++ /dev/null @@ -1,85 +0,0 @@ -package cache - -import chisel3._ -import chisel3.util._ -import cpu.defines._ - -class CacheAXIInterface extends Module { - val io = IO(new Bundle { - val icache = Flipped(new ICache_AXIInterface()) - val dcache = Flipped(new DCache_AXIInterface()) - val axi = new AXI() - }) - - // pass-through aw { - io.axi.aw.bits.id := 1.U - io.axi.aw.bits.addr := io.dcache.aw.bits.addr - io.axi.aw.bits.len := io.dcache.aw.bits.len - io.axi.aw.bits.size := io.dcache.aw.bits.size - io.axi.aw.valid := io.dcache.aw.valid - io.axi.aw.bits.burst := 1.U - io.axi.aw.bits.prot := 0.U - io.axi.aw.bits.cache := 0.U - io.axi.aw.bits.lock := 0.U - io.dcache.aw.ready := io.axi.aw.ready - // pass-through aw } - - // pass-through w { - io.axi.w.bits.id := 1.U - io.axi.w.bits.data := io.dcache.w.bits.data - io.axi.w.bits.strb := io.dcache.w.bits.strb - io.axi.w.bits.last := io.dcache.w.bits.last - io.axi.w.valid := io.dcache.w.valid - io.dcache.w.ready := io.axi.w.ready - // pass-through aw } - - // pass-through b { - io.dcache.b.bits.id := io.axi.b.bits.id - io.dcache.b.valid := io.axi.b.valid - io.dcache.b.bits.resp := io.axi.b.bits.resp - io.axi.b.ready := io.dcache.b.ready - // pass-through b } - - // mux ar { - // we need to lock ar to avoid signals change during handshake - val ar_sel_lock = RegInit(false.B) - val ar_sel_val = RegInit(false.B) - val choose_dcache = Mux(ar_sel_lock, ar_sel_val, !io.icache.ar.valid && io.dcache.ar.valid) - - when(io.axi.ar.valid) { - when(io.axi.ar.ready) { - ar_sel_lock := false.B - }.otherwise { - ar_sel_lock := true.B - ar_sel_val := choose_dcache - } - } - - io.axi.ar.bits.id := Cat(0.U(3.W), choose_dcache) - io.axi.ar.bits.addr := Mux(choose_dcache, io.dcache.ar.bits.addr, io.icache.ar.bits.addr) - io.axi.ar.bits.len := Mux(choose_dcache, io.dcache.ar.bits.len, io.icache.ar.bits.len) - io.axi.ar.bits.size := Mux(choose_dcache, io.dcache.ar.bits.size, io.icache.ar.bits.size) - io.axi.ar.valid := Mux(choose_dcache, io.dcache.ar.valid, io.icache.ar.valid) - io.axi.ar.bits.burst := 1.U - io.axi.ar.bits.prot := 0.U - io.axi.ar.bits.cache := 0.U - io.axi.ar.bits.lock := 0.U - io.icache.ar.ready := !choose_dcache && io.axi.ar.ready - io.dcache.ar.ready := choose_dcache && io.axi.ar.ready - // mux ar } - - // mux r based on rid { - val r_sel = io.axi.r.bits.id(0) - io.icache.r.bits.id := io.axi.r.bits.id - io.icache.r.bits.data := io.axi.r.bits.data - io.icache.r.bits.resp := io.axi.r.bits.resp - io.icache.r.bits.last := io.axi.r.bits.last - io.icache.r.valid := !r_sel && io.axi.r.valid - io.dcache.r.bits.id := io.axi.r.bits.id - io.dcache.r.bits.data := io.axi.r.bits.data - io.dcache.r.bits.resp := io.axi.r.bits.resp - io.dcache.r.bits.last := io.axi.r.bits.last - io.dcache.r.valid := r_sel && io.axi.r.valid - io.axi.r.ready := Mux(r_sel, io.dcache.r.ready, io.icache.r.ready) - // mux r based on rid } -} diff --git a/chisel/playground/src/cache/DCache.scala b/chisel/playground/src/cache/DCache.scala deleted file mode 100644 index 76f03f5..0000000 --- a/chisel/playground/src/cache/DCache.scala +++ /dev/null @@ -1,783 +0,0 @@ -package cache - -import chisel3._ -import chisel3.util._ -import memory._ -import cpu.CacheConfig -import cpu.defines._ -import cpu.CpuConfig -import cpu.defines.Const._ -import icache.mmu.AccessType - -/* - 整个宽度为PADDR_WID的地址 - ========================================================== - | tag | index | offset | - | | | bank index | bank offset | - ========================================================== - - nway 组,nindex 行 - ============================================================== - | valid | dirty | tag | bank 0 | bank 1 | ... | bank n | - | 1 | 1 | | | | | | - ============================================================== - | bank | - | data 0 | data 1 | ... | data n | - | XLEN | XLEN | ... | XLEN | - ===================================== - - 本 CPU 的实现如下: - 每个bank分为多个dataBlocks,每个dataBlocks的宽度为AXI_DATA_WID,这样能方便的和AXI总线进行交互 - RV64实现中AXI_DATA_WID为64,所以每个dataBlocks可以存储1个数据 - 为了简化设计,目前*一个bank中只有一个dataBlocks*,即每个bank中只能存储一个数据 - 这样的话dataBlocks可以被简化掉,直接用bank代替 - //TODO:解决AXI_DATA_WID小于XLEN的情况 - - ============================================================== - | valid | dirty | tag | bank 0 | bank 1 | ... | bank n | - | 1 | 1 | | | | | | - ============================================================== - | bank | - | dataBlocks | - | data 0 | - | 64 | - =================== - */ - -class WriteBufferUnit extends Bundle { - val data = UInt(XLEN.W) - val addr = UInt(XLEN.W) - val strb = UInt(AXI_STRB_WID.W) - val size = UInt(AXI_SIZE_WID.W) -} - -class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Module with HasTlbConst with HasCSRConst { - val nway = cacheConfig.nway - val nindex = cacheConfig.nindex - val nbank = cacheConfig.nbank - val instFetchNum = cpuConfig.instFetchNum - val bankOffsetWidth = cacheConfig.bankOffsetWidth - val bankIndexWidth = cacheConfig.offsetWidth - bankOffsetWidth - val bytesPerBank = cacheConfig.bytesPerBank - val tagWidth = cacheConfig.tagWidth - val indexWidth = cacheConfig.indexWidth - val offsetWidth = cacheConfig.offsetWidth - val bitsPerBank = cacheConfig.bitsPerBank - val writeFifoDepth = 4 - - // 每个bank中存AXI_DATA_WID位的数据 - // TODO:目前的实现只保证了AXI_DATA_WID为XLEN的情况下的正确性 - require(AXI_DATA_WID == XLEN, "AXI_DATA_WID should be greater than XLEN") - - def pAddr = new Bundle { - val tag = UInt(ppnLen.W) - val index = UInt(indexWidth.W) - val offset = UInt(offsetWidth.W) - } - - def bankAddr = new Bundle { - val index = UInt(bankIndexWidth.W) - val offset = UInt(bankOffsetWidth.W) - } - - val io = IO(new Bundle { - val cpu = Flipped(new Cache_DCache()) - val axi = new DCache_AXIInterface() - }) - - // dcache的状态机 - val s_idle :: s_uncached :: s_fence :: s_replace :: s_wait :: s_tlb_refill :: Nil = Enum(6) - val state = RegInit(s_idle) - - // ptw的状态机 - val ptw_handshake :: ptw_send :: ptw_cached :: ptw_uncached :: ptw_check :: ptw_set :: Nil = Enum(6) - val ptw_state = RegInit(ptw_handshake) - - // 临时寄存器 - val ptw_working = - ptw_state =/= ptw_handshake && - ptw_state =/= ptw_set && - !(io.cpu.tlb.ptw.pte.bits.access_fault || io.cpu.tlb.ptw.pte.bits.page_fault) - val ptw_scratch = RegInit(0.U.asTypeOf(new Bundle { - val paddr = pAddr - val replace = Bool() - val dcache_wait = Bool() - })) - - io.cpu.tlb.ptw.vpn.ready := false.B - - // ========================================================== - // | ppn | page offset | - // ---------------------------------------------------------- - // | tag | index | offset | - // | | | bank index | bank offset | - // ========================================================== - - // exe级的index,用于访问第i行的数据 - val exe_index = io.cpu.exe_addr(indexWidth + offsetWidth - 1, offsetWidth) - // mem级的bank的index,用于访问第i个bank的数据 - val bank_index = io.cpu.addr(bankIndexWidth + bankOffsetWidth - 1, bankOffsetWidth) - - // // 一个bank行内存了一个数据,所以bank_offset恒为0 - // val bank_offset = - // if (bankOffsetWidth > log2Ceil(XLEN / 8)) - // io.cpu.addr(bankOffsetWidth - 1, log2Ceil(XLEN / 8)) // 保证地址对齐 - // else - // 0.U - - // axi信号中size的宽度,对于cached段,size为3位 - val cached_size = log2Ceil(AXI_DATA_WID / 8) - val cached_len = (nbank - 1) - - // * valid dirty * // - // 每行有一个有效位和一个脏位 - val valid = RegInit(VecInit(Seq.fill(nindex)(VecInit(Seq.fill(nway)(false.B))))) // FIXME:nway放前面会导致栈溢出错误 - val dirty = RegInit(VecInit(Seq.fill(nindex)(VecInit(Seq.fill(nway)(false.B))))) - val lru = RegInit(VecInit(Seq.fill(nindex)(false.B))) // TODO:支持更多路数,目前只支持2路 - - // 用于指示哪个行的脏位为真 - val dirty_index = Wire(UInt(indexWidth.W)) - dirty_index := PriorityEncoder(dirty.map(_.asUInt.orR)) - // 用于指示哪个路的脏位为真 - val dirty_way = dirty(dirty_index)(1) - - // 表示进入fence的写回状态 - val fence = RegInit(false.B) - - // 读取bank这类sram的数据需要两拍 - val readsram = RegInit(false.B) - - // 对于uncached段使用writeFifo进行写回 - val writeFifo = Module(new Queue(new WriteBufferUnit(), writeFifoDepth)) - val writeFifo_axi_busy = RegInit(false.B) - val writeFifo_busy = writeFifo.io.deq.valid // || writeFifo_axi_busy 应该不需要这个判断 - - writeFifo.io.enq.valid := false.B - writeFifo.io.enq.bits := 0.U.asTypeOf(new WriteBufferUnit()) - writeFifo.io.deq.ready := false.B - - // * victim cache * // - val burst = RegInit(0.U.asTypeOf(new Bundle { - val wstrb = Vec(nway, UInt(nbank.W)) // 用于控制写回哪个bank - })) - - // 用于解决在replace时发生写回时读写时序不一致的问题 - val bank_wbindex = RegInit(0.U((offsetWidth - log2Ceil(XLEN / 8)).W)) - val bank_wbdata = RegInit(VecInit(Seq.fill(nbank)(0.U(XLEN.W)))) - - // 是否使用exe的地址进行提前访存 - val use_next_addr = (state === s_idle) || (state === s_wait) - val do_replace = RegInit(false.B) - // replace index 表示行的索引 - val replace_index = Wire(UInt(indexWidth.W)) - replace_index := io.cpu.addr(indexWidth + offsetWidth - 1, offsetWidth) - val replace_wstrb = Wire(Vec(nbank, Vec(nway, UInt(AXI_STRB_WID.W)))) - val replace_wdata = Mux(state === s_replace, io.axi.r.bits.data, io.cpu.wdata) - - val replace_way = lru(replace_index) - - val replace_dirty = dirty(replace_index)(replace_way) - - val tag_rindex = Mux(use_next_addr, exe_index, replace_index) - val tag_wstrb = RegInit(VecInit(Seq.fill(nway)(false.B))) - val tag_wdata = RegInit(0.U(tagWidth.W)) - - val data = Wire(Vec(nbank, Vec(nway, UInt(XLEN.W)))) - // 使用寄存器类型才能防止idle时tag出现无法hit的错误 - val tag = RegInit(VecInit(Seq.fill(nway)(0.U(tagWidth.W)))) - - val tag_compare_valid = Wire(Vec(nway, Bool())) - val cache_hit = tag_compare_valid.contains(true.B) - - val mmio_read_stall = io.cpu.tlb.uncached && !io.cpu.wen.orR - val mmio_write_stall = io.cpu.tlb.uncached && io.cpu.wen.orR && !writeFifo.io.enq.ready - val cached_stall = !io.cpu.tlb.uncached && !cache_hit - - val select_way = tag_compare_valid(1) - - val dcache_stall = Mux( - state === s_idle, - Mux( - io.cpu.en, - (cached_stall || mmio_read_stall || mmio_write_stall || !io.cpu.tlb.hit), - io.cpu.fence_i || fence - ), - state =/= s_wait - ) - io.cpu.dcache_ready := !dcache_stall - - val saved_rdata = RegInit(0.U(XLEN.W)) - - io.cpu.rdata := Mux(state === s_wait, saved_rdata, data(bank_index)(select_way)) - - io.cpu.tlb.vaddr := io.cpu.addr - io.cpu.tlb.access_type := Mux(io.cpu.en && io.cpu.wen.orR, AccessType.store, AccessType.load) - io.cpu.tlb.en := io.cpu.en - - val bank_raddr = Wire(UInt(indexWidth.W)) - bank_raddr := Mux(state === s_fence, dirty_index, Mux(use_next_addr, exe_index, replace_index)) - val tag_raddr = Mux(state === s_fence, dirty_index, tag_rindex) - - val wstrb = Wire(Vec(nindex, (Vec(nway, UInt(AXI_STRB_WID.W))))) - wstrb := 0.U.asTypeOf(wstrb) - wstrb(bank_index)(select_way) := io.cpu.wstrb - - // bank tagv ram - val tagRam = Seq.fill(nway)(Module(new LUTRam(nindex, tagWidth))) - for { i <- 0 until nway } { - val bank = Seq.fill(nbank)(Module(new SimpleDualPortRam(nindex, AXI_DATA_WID, byteAddressable = true))) - for { j <- 0 until nbank } { - bank(j).io.ren := true.B - bank(j).io.raddr := bank_raddr - data(j)(i) := bank(j).io.rdata - - bank(j).io.wen := replace_wstrb(j)(i).orR - bank(j).io.waddr := replace_index - bank(j).io.wdata := replace_wdata - bank(j).io.wstrb := replace_wstrb(j)(i) - - tagRam(i).io.raddr := tag_raddr - tag(i) := tagRam(i).io.rdata - - tagRam(i).io.wen := tag_wstrb(i) - tagRam(i).io.waddr := replace_index - tagRam(i).io.wdata := tag_wdata - - tag_compare_valid(i) := - tag(i) === io.cpu.tlb.ptag && // tag相同 - valid(replace_index)(i) && // cache行有效位为真 - io.cpu.tlb.hit // 页表有效 - - replace_wstrb(j)(i) := Mux( - tag_compare_valid(i) && io.cpu.en && io.cpu.wen.orR && !io.cpu.tlb.uncached && state === s_idle, - wstrb(j)(i), - Fill(AXI_STRB_WID, burst.wstrb(i)(j)) - ) - } - } - - val ar = RegInit(0.U.asTypeOf(new AR())) - val arvalid = RegInit(false.B) - io.axi.ar.bits <> ar - io.axi.ar.valid := arvalid - val rready = RegInit(false.B) - io.axi.r.ready := rready - val aw = RegInit(0.U.asTypeOf(new AW())) - val awvalid = RegInit(false.B) - io.axi.aw.bits <> aw - io.axi.aw.valid := awvalid - val w = RegInit(0.U.asTypeOf(new W())) - val wvalid = RegInit(false.B) - io.axi.w.bits <> w - io.axi.w.bits.last := w.last && wvalid - io.axi.w.valid := wvalid - - io.axi.b.ready := true.B - - val access_fault = RegInit(false.B) - val page_fault = RegInit(false.B) - // sv39的63-39位需要与第38位相同 - val addr_err = io.cpu - .addr(XLEN - 1, VADDR_WID) - .asBools - .map(_ =/= io.cpu.addr(VADDR_WID - 1)) - .reduce(_ || _) - - io.cpu.access_fault := access_fault - io.cpu.page_fault := page_fault - - // write buffer - when(writeFifo_axi_busy) { - when(io.axi.aw.fire) { - awvalid := false.B - } - when(io.axi.w.fire) { - wvalid := false.B - w.last := false.B - } - when(io.axi.b.fire) { - writeFifo_axi_busy := false.B - } - }.elsewhen(writeFifo.io.deq.valid) { - writeFifo.io.deq.ready := writeFifo.io.deq.valid - when(writeFifo.io.deq.fire) { - aw.addr := writeFifo.io.deq.bits.addr - aw.size := writeFifo.io.deq.bits.size - w.data := writeFifo.io.deq.bits.data - w.strb := writeFifo.io.deq.bits.strb - } - aw.len := 0.U - awvalid := true.B - w.last := true.B - wvalid := true.B - writeFifo_axi_busy := true.B - } - - switch(state) { - is(s_idle) { - access_fault := false.B // 在idle时清除access_fault - page_fault := false.B // 在idle时清除page_fault - when(io.cpu.en) { - when(addr_err) { - access_fault := true.B - }.elsewhen(!io.cpu.tlb.hit) { - state := s_tlb_refill - }.elsewhen(io.cpu.tlb.uncached) { - when(io.cpu.wen.orR) { - when(writeFifo.io.enq.ready) { - writeFifo.io.enq.valid := true.B - writeFifo.io.enq.bits.addr := io.cpu.tlb.paddr - writeFifo.io.enq.bits.size := io.cpu.rlen - writeFifo.io.enq.bits.strb := io.cpu.wstrb - writeFifo.io.enq.bits.data := io.cpu.wdata - - when(!io.cpu.complete_single_request) { - state := s_wait - } - } - }.elsewhen(!writeFifo_busy) { - ar.addr := io.cpu.tlb.paddr - ar.len := 0.U - ar.size := io.cpu.rlen - arvalid := true.B - state := s_uncached - rready := true.B - } // when store buffer busy, read will stop at s_idle but stall pipeline. - }.otherwise { - when(!cache_hit) { - state := s_replace - }.otherwise { - when(!dcache_stall) { - // update lru and mark dirty - replace_way := ~select_way - when(io.cpu.wen.orR) { - dirty(replace_index)(select_way) := true.B - } - when(!io.cpu.complete_single_request) { - saved_rdata := data(bank_index)(select_way) - state := s_wait - } - } - } - } - }.otherwise { - io.cpu.tlb.ptw.vpn.ready := !ptw_working - when(io.cpu.fence_i) { - // fence.i 需要将所有脏位为true的行写回 - when(dirty.asUInt.orR) { - when(!writeFifo_busy) { - state := s_fence - readsram := false.B // bank读数据要两拍 - } - }.otherwise { - // 当所有脏位为fault时,fence.i可以直接完成 - state := s_wait - } - } - } - } - is(s_uncached) { - when(arvalid && io.axi.ar.ready) { - arvalid := false.B - } - when(io.axi.r.fire) { - rready := false.B - saved_rdata := io.axi.r.bits.data - access_fault := io.axi.r.bits.resp =/= RESP_OKEY.U - state := s_wait - } - } - is(s_fence) { - when(fence) { - when(io.axi.aw.fire) { - awvalid := false.B - } - when(io.axi.w.fire) { - when(w.last) { - wvalid := false.B - }.otherwise { - bank_wbindex := bank_wbindex + 1.U - w.data := data(bank_wbindex + 1.U)(dirty_way) - when(bank_wbindex + 1.U === (cached_len).U) { - w.last := true.B - } - } - } - when(io.axi.b.valid) { - // TODO: 增加此处的acc_err错误处理 - // acc_err := io.axi.b.bits.resp =/= RESP_OKEY.U - dirty(dirty_index)(dirty_way) := false.B // 写回完成,清除脏位 - fence := false.B - } - }.elsewhen(dirty.asUInt.orR) { - readsram := true.B - when(readsram) { - // for axi write - readsram := false.B - aw.addr := Cat( - Mux(dirty_way === 0.U, tagRam(0).io.rdata, tagRam(1).io.rdata), - dirty_index, - 0.U(offsetWidth.W) - ) - aw.len := cached_len.U - aw.size := cached_size.U - awvalid := true.B - w.data := data(0)(dirty_way) // 从第零块bank开始写回 - w.strb := ~0.U(AXI_STRB_WID.W) - w.last := false.B - wvalid := true.B - bank_wbindex := 0.U - fence := true.B - } - }.otherwise { - state := s_wait - } - } - is(s_replace) { - // 防止和写队列冲突 - when(!writeFifo_busy) { - when(do_replace) { - when(replace_dirty) { - when(io.axi.aw.fire) { - awvalid := false.B - } - when(io.axi.w.fire) { - when(w.last) { - wvalid := false.B - }.otherwise { - bank_wbindex := bank_wbindex + 1.U - w.data := bank_wbdata(bank_wbindex + 1.U) - when(bank_wbindex + 1.U === (cached_len).U) { - w.last := true.B - } - } - } - when(io.axi.b.valid) { - // TODO: 增加此处的acc_err错误处理 - // acc_err := io.axi.b.bits.resp =/= RESP_OKEY.U - replace_dirty := false.B // 写回完成,清除脏位 - } - } //上面都是写回部分的代码 - when(io.axi.ar.fire) { - tag_wstrb(replace_way) := false.B - arvalid := false.B - } - when(io.axi.r.fire) { - when(io.axi.r.bits.last) { - rready := false.B - burst.wstrb(replace_way) := 0.U - }.otherwise { - burst.wstrb(replace_way) := burst.wstrb(replace_way) << 1 - } - } - when( - (!replace_dirty || io.axi.b.valid) && // 不需要替换或写回完成 - ((io.axi.r.valid && io.axi.r.bits.last) || !rready) // 读取完成 - ) { - valid(replace_index)(replace_way) := true.B - do_replace := false.B - ptw_scratch.replace := false.B - when(ptw_working && io.cpu.tlb.ptw.access_type =/= AccessType.fetch) { - // ptw复用的模式 - state := s_tlb_refill - }.otherwise { - when(ptw_scratch.dcache_wait && !io.cpu.complete_single_request) { - state := s_wait - }.otherwise { - ptw_scratch.dcache_wait := false.B - state := s_idle - } - } - } - }.otherwise { - // 增加了一拍,用于sram读取数据 - readsram := true.B - when(readsram) { - readsram := false.B - do_replace := true.B - ar.len := cached_len.U - ar.size := cached_size.U // 8 字节 - arvalid := true.B - rready := true.B - burst.wstrb(replace_way) := 1.U // 先写入第一块bank - tag_wstrb(replace_way) := true.B - when(!ptw_working) { - // dcache的普通模式 - // for ar axi - ar.addr := Cat(io.cpu.tlb.paddr(PADDR_WID - 1, offsetWidth), 0.U(offsetWidth.W)) - tag_wdata := io.cpu.tlb.ptag - }.otherwise { - // ptw复用的模式 - ar.addr := Cat(ptw_scratch.paddr.tag, ptw_scratch.paddr.index, 0.U(offsetWidth.W)) - tag_wdata := ptw_scratch.paddr.tag - } - when(replace_dirty) { - // cache行的脏位为真时需要写回,备份一下cache行,便于处理读写时序问题 - (0 until nbank).map(i => bank_wbdata(i) := data(i)(replace_way)) - aw.addr := Cat(tag(replace_way), replace_index, 0.U(offsetWidth.W)) - aw.len := cached_len.U - aw.size := cached_size.U - awvalid := true.B - w.data := data(0)(replace_way) - w.strb := ~0.U(AXI_STRB_WID.W) - w.last := false.B - wvalid := true.B - bank_wbindex := 0.U - } - } - } - } - } - is(s_wait) { - // 等待流水线的allow_to_go信号,防止多次发出读、写请求 - io.cpu.tlb.ptw.vpn.ready := !ptw_working - ptw_scratch.dcache_wait := true.B - when(io.cpu.complete_single_request) { - ptw_scratch.dcache_wait := false.B - access_fault := false.B // 清除access_fault - page_fault := false.B // 清除page_fault - state := s_idle - } - } - is(s_tlb_refill) { - io.cpu.tlb.ptw.vpn.ready := !ptw_working - when(io.cpu.tlb.access_fault) { - access_fault := true.B - state := s_wait - }.elsewhen(io.cpu.tlb.page_fault) { - page_fault := true.B - state := s_wait - }.otherwise { - when(io.cpu.tlb.hit) { - state := s_idle - } - } - } - } - - // ========================================================== - // 实现页表访问,回填tlb - val satp = io.cpu.tlb.csr.satp.asTypeOf(satpBundle) - val mstatus = io.cpu.tlb.csr.mstatus.asTypeOf(new Mstatus) - val mode = Mux(io.cpu.tlb.access_type === AccessType.fetch, io.cpu.tlb.csr.imode, io.cpu.tlb.csr.dmode) - val sum = mstatus.sum - val mxr = mstatus.mxr - val vpn = io.cpu.tlb.ptw.vpn.bits.asTypeOf(vpnBundle) - val access_type = io.cpu.tlb.ptw.access_type - val ppn = RegInit(0.U(ppnLen.W)) - val vpn_index = RegInit(0.U(log2Up(level).W)) // 页表访问的层级 - val pte = RegInit(0.U.asTypeOf(pteBundle)) // 页表项 - - io.cpu.tlb.ptw.pte.valid := false.B - io.cpu.tlb.ptw.pte.bits := DontCare - io.cpu.tlb.ptw.pte.bits.access_fault := false.B - io.cpu.tlb.ptw.pte.bits.page_fault := false.B - io.cpu.tlb.complete_single_request := io.cpu.complete_single_request - require(AXI_DATA_WID == XLEN) // 目前只考虑了AXI_DATA_WID == XLEN的情况 - - def raisePageFault(): Unit = { - io.cpu.tlb.ptw.pte.valid := true.B - io.cpu.tlb.ptw.pte.bits.page_fault := true.B - ptw_state := ptw_handshake - } - - def modeCheck(): Unit = { - switch(mode) { - is(ModeS) { - when(pte.flag.u && !sum) { - raisePageFault() - }.otherwise { - ptw_state := ptw_set - } - } - is(ModeU) { - when(!pte.flag.u) { - raisePageFault() - }.otherwise { - ptw_state := ptw_set - } - } - } - } - - switch(ptw_state) { - is(ptw_handshake) { // 0 - // 页表访问虚地址握手 - when(io.cpu.tlb.ptw.vpn.fire) { - vpn_index := (level - 1).U - ppn := satp.ppn - ptw_state := ptw_send - } - } - is(ptw_send) { // 1 - val vpnn = Mux1H( - Seq( - (vpn_index === 0.U) -> vpn.vpn0, - (vpn_index === 1.U) -> vpn.vpn1, - (vpn_index === 2.U) -> vpn.vpn2 - ) - ) - val ptw_addr = paddrApply(ppn, vpnn).asTypeOf(pAddr) - val pte_uncached = AddressSpace.isMMIO(ptw_addr.asUInt) - when(pte_uncached) { - arvalid := true.B - ar.addr := ptw_addr.asUInt - ar.size := log2Ceil(AXI_DATA_WID / 8).U // 一个pte的大小是8字节 - ar.len := 0.U // 读一拍即可 - rready := true.B - ptw_state := ptw_uncached - }.otherwise { - bank_raddr := ptw_addr.index - tagRam.map(_.io.raddr := ptw_addr.index) - replace_index := ptw_addr.index - ptw_state := ptw_cached - ptw_scratch.paddr := ptw_addr - ptw_scratch.replace := false.B - } - } - is(ptw_cached) { // 2 - bank_raddr := ptw_scratch.paddr.index - tagRam.map(_.io.raddr := ptw_scratch.paddr.index) - replace_index := ptw_scratch.paddr.index - for { i <- 0 until nway } { - tag_compare_valid(i) := - tag(i) === ptw_scratch.paddr.tag && // tag相同 - valid(ptw_scratch.paddr.index)(i) // cache行有效位为真 - } - when(!ptw_scratch.replace) { - when(cache_hit) { - val pte_temp = data(ptw_scratch.paddr.offset.asTypeOf(bankAddr).index)(select_way).asTypeOf(pteBundle) - when(!pte_temp.flag.v || !pte_temp.flag.r && pte_temp.flag.w) { - raisePageFault() - }.otherwise { - when(pte_temp.flag.r || pte_temp.flag.x) { - // 找到了叶子页 - pte := pte_temp - ptw_state := ptw_check - }.otherwise { - // 该pte指向下一个页表 - vpn_index := vpn_index - 1.U - when(vpn_index - 1.U < 0.U) { - raisePageFault() - }.otherwise { - ppn := pte_temp.ppn - ptw_state := ptw_send - } - } - } - }.otherwise { - ptw_scratch.replace := true.B - state := s_replace // 直接复用dcache的replace状态机,帮我们进行replace操作 - } - } - } - is(ptw_uncached) { // 3 - when(io.axi.ar.fire) { - arvalid := false.B - } - when(io.axi.r.fire) { - rready := false.B - val pte_temp = io.axi.r.bits.data.asTypeOf(pteBundle) - when(!pte_temp.flag.v || !pte_temp.flag.r && pte_temp.flag.w) { - raisePageFault() - }.otherwise { - when(pte_temp.flag.r || pte_temp.flag.x) { - // 找到了叶子页 - pte := pte_temp - ptw_state := ptw_check - }.otherwise { - // 该pte指向下一个页表 - vpn_index := vpn_index - 1.U - when(vpn_index - 1.U < 0.U) { - raisePageFault() - }.otherwise { - ppn := pte_temp.ppn - ptw_state := ptw_send - } - } - } - } - } - is(ptw_check) { // 4 - // 检查权限 - switch(access_type) { - is(AccessType.load) { - when(mxr) { - when(!pte.flag.r && !pte.flag.x) { - raisePageFault() - }.otherwise { - modeCheck() - } - }.otherwise { - when(!pte.flag.r) { - raisePageFault() - }.otherwise { - modeCheck() - } - } - } - is(AccessType.store) { - when(!pte.flag.w) { - raisePageFault() - }.otherwise { - modeCheck() - } - } - is(AccessType.fetch) { - when(!pte.flag.x) { - raisePageFault() - }.otherwise { - modeCheck() - } - } - } - } - is(ptw_set) { // 5 - when( - vpn_index > 0.U && ( - vpn_index === 1.U && pte.ppn.asTypeOf(ppnBundle).ppn0.orR || - vpn_index === 2.U && (pte.ppn.asTypeOf(ppnBundle).ppn1.orR || pte.ppn.asTypeOf(ppnBundle).ppn0.orR) - ) - ) { - raisePageFault() - }.elsewhen(!pte.flag.a || access_type === AccessType.store && !pte.flag.d) { - raisePageFault() // 使用软件的方式设置脏位以及访问位 - }.otherwise { - // 翻译成功 - val rmask = WireInit(~0.U(maskLen.W)) - io.cpu.tlb.ptw.pte.valid := true.B - io.cpu.tlb.ptw.pte.bits.rmask := rmask - io.cpu.tlb.ptw.pte.bits.entry := pte - val ppn_set = Wire(ppnBundle) - when(vpn_index === 2.U) { - ppn_set.ppn2 := pte.ppn.asTypeOf(ppnBundle).ppn2 - ppn_set.ppn1 := vpn.vpn1 - ppn_set.ppn0 := vpn.vpn0 - rmask := 0.U - }.elsewhen(vpn_index === 1.U) { - ppn_set.ppn2 := pte.ppn.asTypeOf(ppnBundle).ppn2 - ppn_set.ppn1 := pte.ppn.asTypeOf(ppnBundle).ppn1 - ppn_set.ppn0 := vpn.vpn0 - rmask := Cat(Fill(ppn1Len, true.B), 0.U(ppn0Len.W)) - }.otherwise { - ppn_set := pte.ppn.asTypeOf(ppnBundle) - } - io.cpu.tlb.ptw.pte.bits.entry.ppn := ppn_set.asUInt - - ptw_state := ptw_handshake - } - } - } - - println("----------------------------------------") - println("DCache: ") - println("nindex: " + nindex) - println("nbank: " + nbank) - println("bitsPerBank: " + bitsPerBank) - println("bankOffsetWidth: " + bankOffsetWidth) - println("bankIndexWidth: " + bankIndexWidth) - println("tagWidth: " + tagWidth) - println("indexWidth: " + indexWidth) - println("offsetWidth: " + offsetWidth) - println("----------------------------------------") -} diff --git a/chisel/playground/src/cache/ICache.scala b/chisel/playground/src/cache/ICache.scala deleted file mode 100644 index 04c0264..0000000 --- a/chisel/playground/src/cache/ICache.scala +++ /dev/null @@ -1,367 +0,0 @@ -package cache - -import chisel3._ -import chisel3.util._ -import memory._ -import cpu.CacheConfig -import cpu.defines._ -import cpu.CpuConfig -import cpu.defines.Const._ - -/* - 整个宽度为PADDR_WID的地址 - ========================================================== - | tag | index | offset | - | | | bank index | bank offset | - ========================================================== - - nway 组,nindex 行 - ====================================================== - | valid | tag | bank 0 | bank 1 | ... | bank n | - | 1 | | | | | | - ====================================================== - | bank | - | inst 0 | inst 1 | ... | inst n | - | 32 | 32 | ... | 32 | - ===================================== - - 本CPU的实现如下: - 每个bank分为多个instBlocks,每个instBlocks的宽度为AXI_DATA_WID,这样能方便的和AXI总线进行交互 - RV64实现中AXI_DATA_WID为64,所以每个instBlocks可以存储2条指令 - 而instBlocks的个数会和instFetchNum相关 - - 当instFetchNum为4时,instBlocks的个数为2 - - 当instFetchNum为2时,instBlocks的个数为1 - 读取数据时会将一个bank中的所有instBlocks读取出来,然后再将instBlocks中的数据按照偏移量重新排列 - 这样的设计可以保证一个bank的指令数对应instFetchNum - - ====================================================== - | valid | tag | bank 0 | bank 1 | ... | bank n | - | 1 | | | | | | - ====================================================== - | bank | - | instBlocks | instBlocks | - | inst 0 | inst 1 | inst 0 | inst 1 | - | 32 | 32 | 32 | 32 | - ===================================== - */ - -class ICache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Module with HasTlbConst { - val nway = cacheConfig.nway - val nindex = cacheConfig.nindex - val nbank = cacheConfig.nbank - val instFetchNum = cpuConfig.instFetchNum - val bankOffsetWidth = cacheConfig.bankOffsetWidth - val bankIndexWidth = cacheConfig.offsetWidth - bankOffsetWidth - val bytesPerBank = cacheConfig.bytesPerBank - val tagWidth = cacheConfig.tagWidth - val indexWidth = cacheConfig.indexWidth - val offsetWidth = cacheConfig.offsetWidth - val bitsPerBank = cacheConfig.bitsPerBank - - def pAddr = new Bundle { - val tag = UInt(ppnLen.W) - val index = UInt(indexWidth.W) - val offset = UInt(offsetWidth.W) - } - - def bankAddr = new Bundle { - val index = UInt(bankIndexWidth.W) - val offset = UInt(bankOffsetWidth.W) - } - - val io = IO(new Bundle { - val cpu = Flipped(new Cache_ICache()) - val axi = new ICache_AXIInterface() - }) - require(isPow2(instFetchNum), "ninst must be power of 2") - require(instFetchNum == bytesPerBank / 4, "instFetchNum must equal to instperbank") - require( - bitsPerBank >= AXI_DATA_WID && bitsPerBank % AXI_DATA_WID == 0, - "bitsPerBank must be greater than AXI_DATA_WID" - ) - - // 一个bank是bitsPerBank宽度,一个bank中有instFetchNum个指令 - // 每个bank中指令块的个数,一个指令块是AXI_DATA_WID宽度 - val instBlocksPerBank = bitsPerBank / AXI_DATA_WID - - val bank_index = io.cpu.addr(0)(offsetWidth - 1, bankOffsetWidth) - val bank_offset = io.cpu.addr(0)(bankOffsetWidth - 1, log2Ceil(INST_WID / 8)) // PC低2位必定是0 - - // * fsm * // - val s_idle :: s_uncached :: s_replace :: s_wait :: s_fence :: s_tlb_refill :: Nil = Enum(6) - val state = RegInit(s_idle) - - // nway 路,每路 nindex 行,每行 nbank 个 bank,每行的nbank共用一个valid - val valid = RegInit(VecInit(Seq.fill(nway)(VecInit(Seq.fill(nindex)(false.B))))) - - // * should choose next addr * // - val use_next_addr = (state === s_idle) || (state === s_wait) - - // 读取一个cache条目中的所有bank行 - val data = Wire(Vec(nway, Vec(nbank, Vec(instBlocksPerBank, UInt(AXI_DATA_WID.W))))) - val data_rindex = io.cpu.addr(use_next_addr)(indexWidth + offsetWidth - 1, offsetWidth) - - val tag = RegInit(VecInit(Seq.fill(nway)(0.U(tagWidth.W)))) - val tag_raddr = io.cpu.addr(use_next_addr)(indexWidth + offsetWidth - 1, offsetWidth) - val tag_wstrb = RegInit(VecInit(Seq.fill(nway)(false.B))) - val tag_wdata = RegInit(0.U(tagWidth.W)) - - // * lru * //// TODO:检查lru的正确性,增加可拓展性,目前只支持两路的cache - val lru = RegInit(VecInit(Seq.fill(nindex)(false.B))) - - val replace_index = io.cpu.addr(0)(indexWidth + offsetWidth - 1, offsetWidth) - // 需要替换的路号 - val replace_way = lru(replace_index) - - // 用于控制写入一行cache条目中的哪个bank, 一个bank可能有多次写入 - val replace_wstrb = RegInit( - VecInit(Seq.fill(nway)(VecInit(Seq.fill(nbank)(VecInit(Seq.fill(instBlocksPerBank)((false.B))))))) - ) - - // * cache hit * // - val tag_compare_valid = VecInit(Seq.tabulate(nway)(i => tag(i) === io.cpu.tlb.ptag && valid(i)(replace_index))) - val cache_hit = tag_compare_valid.contains(true.B) - val cache_hit_available = cache_hit && io.cpu.tlb.hit && !io.cpu.tlb.uncached - val select_way = tag_compare_valid(1) // 1路命中时值为1,0路命中时值为0 //TODO:支持更多路数 - - // 将一个 bank 中的指令分成 instFetchNum 份,每份 INST_WID bit - val inst_in_bank = VecInit( - Seq.tabulate(instFetchNum)(i => data(select_way)(bank_index).asUInt((i + 1) * INST_WID - 1, i * INST_WID)) - ) - - // 将 inst_in_bank 中的指令按照 bank_offset 位偏移量重新排列 - // 处理偏移导致的跨 bank 读取 - // 当offset为0时,不需要重新排列 - // 当offset为1时,此时发送到cpu的inst0应该是inst1,inst1应该无数据,并设置对应的valid - val inst = VecInit( - Seq.tabulate(instFetchNum)(i => - Mux( - i.U <= ((instFetchNum - 1).U - bank_offset), - inst_in_bank(i.U + bank_offset), - 0.U - ) - ) - ) - val inst_valid = VecInit( - Seq.tabulate(instFetchNum)(i => cache_hit_available && i.U <= ((instFetchNum - 1).U - bank_offset)) - ) - - val rdata_in_wait = RegInit(VecInit(Seq.fill(instFetchNum)(0.U.asTypeOf(new Bundle { - val inst = UInt(INST_WID.W) - val valid = Bool() - })))) - - // 对于可缓存段访存时读取的数据宽度应该和AXI_DATA的宽度相同 - val cached_size = log2Ceil(AXI_DATA_WID / 8) - val cached_len = (nbank * instBlocksPerBank - 1) - // 对于不可缓存段访存时读取的数据宽度应该和指令宽度相同 - val uncached_size = log2Ceil(INST_WID / 8) - val uncached_len = 0 - - // bank tag ram - for { i <- 0 until nway } { - // 每一个条目中有nbank个bank,每个bank存储instFetchNum个指令 - // 每次写入cache时将写完一整个cache行 - val bank = - Seq.fill(nbank)( - Seq.fill(instBlocksPerBank)( - Module(new SimpleDualPortRam(depth = nindex, width = AXI_DATA_WID, byteAddressable = false)) - ) - ) - for { j <- 0 until nbank } { - for { k <- 0 until instBlocksPerBank } { - bank(j)(k).io.ren := true.B - bank(j)(k).io.raddr := data_rindex - data(i)(j)(k) := bank(j)(k).io.rdata - - bank(j)(k).io.wen := replace_wstrb(i)(j)(k) - bank(j)(k).io.waddr := replace_index - bank(j)(k).io.wdata := io.axi.r.bits.data - bank(j)(k).io.wstrb := replace_wstrb(i)(j)(k) - } - } - } - - for { i <- 0 until instFetchNum } { - io.cpu.inst_valid(i) := Mux(state === s_idle, inst_valid(i), rdata_in_wait(i).valid) && io.cpu.req - io.cpu.inst(i) := Mux(state === s_idle, inst(i), rdata_in_wait(i).inst) - } - - for { i <- 0 until nway } { - // 实例化了nway个tag ram - val tagBram = Module(new LUTRam(nindex, tagWidth)) - tagBram.io.raddr := tag_raddr - tag(i) := tagBram.io.rdata - - tagBram.io.wen := tag_wstrb(i) - tagBram.io.waddr := replace_index - tagBram.io.wdata := tag_wdata - } - - io.cpu.icache_stall := Mux(state === s_idle, (!cache_hit_available && io.cpu.req), state =/= s_wait) - - io.cpu.tlb.vaddr := io.cpu.addr(0) - io.cpu.tlb.complete_single_request := io.cpu.complete_single_request - io.cpu.tlb.en := io.cpu.req && (state === s_idle || state === s_tlb_refill) - - val ar = RegInit(0.U.asTypeOf(new AR())) - val arvalid = RegInit(false.B) - ar <> io.axi.ar.bits - arvalid <> io.axi.ar.valid - - val r = RegInit(0.U.asTypeOf(new R())) - val rready = RegInit(false.B) - r <> io.axi.r.bits - rready <> io.axi.r.ready - - val access_fault = RegInit(false.B) - val page_fault = RegInit(false.B) - val addr_misaligned = RegInit(false.B) - // sv39的63-39位不与第38位相同,或者地址未对齐时,地址错 - val addr_err = - io.cpu - .addr(use_next_addr)(XLEN - 1, VADDR_WID) - .asBools - .map(_ =/= io.cpu.addr(use_next_addr)(VADDR_WID - 1)) - .reduce(_ || _) || - io.cpu.addr(use_next_addr)(log2Ceil(INST_WID / 8) - 1, 0).orR - - io.cpu.access_fault := access_fault //TODO:实现cached段中的访存response错误 - io.cpu.page_fault := page_fault - io.cpu.addr_misaligned := addr_misaligned - - switch(state) { - is(s_idle) { - access_fault := false.B // 在idle时清除access_fault - page_fault := false.B // 在idle时清除page_fault - addr_misaligned := false.B // 在idle时清除addr_misaligned - when(io.cpu.req) { - when(addr_err) { - when(io.cpu.addr(use_next_addr)(log2Ceil(INST_WID / 8) - 1, 0).orR) { - addr_misaligned := true.B - }.otherwise { - access_fault := true.B - } - state := s_wait - rdata_in_wait(0).inst := Instructions.NOP - rdata_in_wait(0).valid := true.B - }.elsewhen(!io.cpu.tlb.hit) { - state := s_tlb_refill - }.elsewhen(io.cpu.tlb.uncached) { - state := s_uncached - ar.addr := io.cpu.tlb.paddr - ar.len := uncached_len.U - ar.size := uncached_size.U - arvalid := true.B - }.elsewhen(!cache_hit) { - state := s_replace - // 取指时按bank块取指 - ar.addr := Cat(io.cpu.tlb.paddr(PADDR_WID - 1, offsetWidth), 0.U(offsetWidth.W)) - ar.len := cached_len.U - ar.size := cached_size.U - arvalid := true.B - - replace_wstrb(replace_way).map(_.map(_ := false.B)) - replace_wstrb(replace_way)(0)(0) := true.B // 从第一个bank的第一个指令块开始写入 - tag_wstrb(replace_way) := true.B - tag_wdata := io.cpu.tlb.ptag - valid(replace_way)(replace_index) := true.B - }.elsewhen(!io.cpu.icache_stall) { - replace_way := ~select_way - when(!io.cpu.complete_single_request) { - state := s_wait - (1 until instFetchNum).foreach(i => rdata_in_wait(i).inst := inst(i)) - (0 until instFetchNum).foreach(i => rdata_in_wait(i).valid := inst_valid(i)) - } - } - } - } - is(s_uncached) { - when(io.axi.ar.valid) { - when(io.axi.ar.ready) { - arvalid := false.B - rready := true.B - } - }.elsewhen(io.axi.r.fire) { - // * uncached not support burst transport * // - rdata_in_wait(0).inst := Mux(ar.addr(2), io.axi.r.bits.data(63, 32), io.axi.r.bits.data(31, 0)) - rdata_in_wait(0).valid := true.B - rready := false.B - access_fault := io.axi.r.bits.resp =/= RESP_OKEY.U - state := s_wait - } - } - is(s_replace) { - when(io.axi.ar.valid) { - when(io.axi.ar.ready) { - arvalid := false.B - rready := true.B - } - }.elsewhen(io.axi.r.fire) { - // * burst transport * // - when(!io.axi.r.bits.last) { - // 左移写掩码,写入下一个bank,或是同一个bank的下一个指令 - replace_wstrb(replace_way) := - ((replace_wstrb(replace_way).asUInt << 1)).asTypeOf(replace_wstrb(replace_way)) - }.otherwise { - rready := false.B - replace_wstrb(replace_way).map(_.map(_ := false.B)) - tag_wstrb(replace_way) := false.B - } - }.elsewhen(!io.axi.r.ready) { - state := s_idle - } - } - is(s_wait) { - // 等待流水线的allow_to_go信号,防止多次发出读请求 - when(io.cpu.complete_single_request) { - access_fault := false.B // 清除access_fault - page_fault := false.B // 清除page_fault - addr_misaligned := false.B // 清除addr_misaligned - state := s_idle - (0 until instFetchNum).foreach(i => rdata_in_wait(i).valid := false.B) - } - } - is(s_fence) { - // 等待dcache完成写回操作,且等待axi总线完成读取操作,因为icache发生状态转移时可能正在读取数据 - when(!io.cpu.dcache_stall && !io.axi.r.valid) { - state := s_idle - } - } - is(s_tlb_refill) { - when(io.cpu.tlb.access_fault) { - access_fault := true.B - state := s_wait - rdata_in_wait(0).inst := Instructions.NOP - rdata_in_wait(0).valid := true.B - }.elsewhen(io.cpu.tlb.page_fault) { - page_fault := true.B - state := s_wait - rdata_in_wait(0).inst := Instructions.NOP - rdata_in_wait(0).valid := true.B - }.otherwise { - when(io.cpu.tlb.hit) { - state := s_idle - } - } - } - } - - // * fence * // - // 不论icache在什么状态,fence指令优先度最高,会强制将icache状态转移为s_fence - when(io.cpu.fence_i) { - valid := 0.U.asTypeOf(valid) // fence.i指令需要icache,等同于将所有valid位置0 - state := s_fence - } - - println("----------------------------------------") - println("ICache: ") - println("nindex: " + nindex) - println("nbank: " + nbank) - println("bankOffsetWidth: " + bankOffsetWidth) - println("bytesPerBank: " + bytesPerBank) - println("tagWidth: " + tagWidth) - println("indexWidth: " + indexWidth) - println("offsetWidth: " + offsetWidth) - println("----------------------------------------") -} diff --git a/chisel/playground/src/cache/memory/LUTRam.scala b/chisel/playground/src/cache/memory/LUTRam.scala deleted file mode 100644 index 7a099ce..0000000 --- a/chisel/playground/src/cache/memory/LUTRam.scala +++ /dev/null @@ -1,64 +0,0 @@ -package cache.memory - -import chisel3._ -import chisel3.util._ -import cpu.CpuConfig - -/** LUT ram for XPM, one port for read/write, one port for read - * @param depth - * how many lines there are in the bank - * @param width - * how wide in bits each line is - * @param config - * implicit configuration to control generate ram for simulation or elaboration - */ -class LUTRam(depth: Int, width: Int)(implicit val cpuConfig: CpuConfig) extends Module { - require(isPow2(depth)) - val waddridth = log2Ceil(depth) - val io = IO(new Bundle { - val raddr = Input(UInt(waddridth.W)) - val rdata = Output(UInt(width.W)) - - val waddr = Input(UInt(waddridth.W)) - val wdata = Input(UInt(width.W)) - val wen = Input(Bool()) - val writeOutput = Output(UInt(width.W)) - }) - - if (cpuConfig.build) { - val bank = Module( - new LUTRamIP( - wdataidth = width, - waddridth = waddridth, - byteWriteWidth = width, - numberOfLines = depth - ) - ) - bank.io.clka := clock - bank.io.clkb := clock - bank.io.rsta := reset - bank.io.rstb := reset - - bank.io.regcea := false.B - bank.io.regceb := false.B - bank.io.ena := true.B - bank.io.enb := true.B - - bank.io.addra := io.waddr - bank.io.wea := io.wen - bank.io.dina := io.wdata - io.writeOutput := DontCare - - bank.io.addrb := io.raddr - io.rdata := bank.io.doutb - } else { - val bank = RegInit(VecInit(Seq.fill(depth)(0.U(width.W)))) - io.rdata := bank(io.raddr) - io.writeOutput := DontCare - when(io.wen) { - bank(io.waddr) := io.wdata - }.otherwise { - io.writeOutput := bank(io.waddr) - } - } -} diff --git a/chisel/playground/src/cache/memory/LUTRamIP.scala b/chisel/playground/src/cache/memory/LUTRamIP.scala deleted file mode 100644 index 91aac49..0000000 --- a/chisel/playground/src/cache/memory/LUTRamIP.scala +++ /dev/null @@ -1,65 +0,0 @@ -package cache.memory - -import chisel3._ -import chisel3.util.log2Ceil - -/** XPM 2019.2 XPM_MEMORY_DPDISTRAM, at page 124 of UG953(2019.2) by default, this is initialized to - * all 0 - * - * @param wdataidth - * : the size of the data to store in each line, in bits - * @param waddridth - * : the width of request - * @param byteWriteWidth - * : addressable size of write - * @param numberOfLines - * : how many **bits** there are in the memory - */ -class LUTRamIP(wdataidth: Int, waddridth: Int, byteWriteWidth: Int, numberOfLines: Int) - extends BlackBox( - Map( - "ADDR_WIDTH_A" -> waddridth, - "ADDR_WIDTH_B" -> waddridth, - "MEMORY_SIZE" -> numberOfLines * wdataidth, - "WRITE_DATA_WIDTH_A" -> wdataidth, - "READ_DATA_WIDTH_A" -> wdataidth, - "READ_DATA_WIDTH_B" -> wdataidth, - "BYTE_WRITE_WIDTH_A" -> byteWriteWidth, - "READ_LATENCY_A" -> 0, - "READ_LATENCY_B" -> 0, - "READ_RESET_VALUE_A" -> 0, - "READ_RESET_VALUE_B" -> 0, - "CLOCKING_MODE" -> "common_clock", - ), - ) { - override def desiredName: String = "xpm_memory_dpdistram" - require( - waddridth == log2Ceil(numberOfLines), - "request width should be log 2 of number of lines to request all", - ) - require( - wdataidth - (wdataidth / byteWriteWidth) * byteWriteWidth == 0, - "data width should be a multiple of byte write width", - ) - require(waddridth <= 20, "request width should be 1 to 20") - val io = IO(new Bundle { - val clka = Input(Clock()) - val clkb = Input(Clock()) - val rsta = Input(Reset()) - val rstb = Input(Reset()) - - val ena = Input(Bool()) - val enb = Input(Bool()) - val regcea = Input(Bool()) - val regceb = Input(Bool()) - - val dina = Input(UInt(wdataidth.W)) - val addra = Input(UInt(waddridth.W)) - val addrb = Input(UInt(waddridth.W)) - - val wea = Input(UInt((wdataidth / byteWriteWidth).W)) - - val douta = Output(UInt(wdataidth.W)) - val doutb = Output(UInt(wdataidth.W)) - }) -} diff --git a/chisel/playground/src/cache/memory/PortDefinitions.scala b/chisel/playground/src/cache/memory/PortDefinitions.scala deleted file mode 100644 index 0c587ab..0000000 --- a/chisel/playground/src/cache/memory/PortDefinitions.scala +++ /dev/null @@ -1,37 +0,0 @@ -package cache.memory - -import chisel3._ -import chisel3.util._ -import cpu.CacheConfig - -class ReadOnlyPort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle { - val addr = Input(UInt(log2Ceil(cacheConfig.nindex * cacheConfig.nbank).W)) - val data = Output(gen) -} - -class WriteOnlyPort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle { - val addr = Input(UInt(log2Ceil(cacheConfig.nindex * cacheConfig.nbank).W)) - val en = Input(Bool()) - val data = Input(gen) -} - -class WriteOnlyMaskPort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle { - val addr = Input(UInt(log2Ceil(cacheConfig.nindex * cacheConfig.nbank).W)) - val en = Input(UInt(cacheConfig.bytesPerBank.W)) - val data = Input(gen) -} - - -class ReadWritePort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle { - val addr = Input(UInt(log2Ceil(cacheConfig.nindex * cacheConfig.nbank).W)) - val en = Input(Bool()) - val wdata = Input(gen) - val rdata = Output(gen) -} - -class MaskedReadWritePort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle { - val addr = Input(UInt(log2Ceil(cacheConfig.nindex * cacheConfig.nbank).W)) - val writeMask = Input(UInt(cacheConfig.bytesPerBank.W)) - val wdata = Input(gen) - val rdata = Output(gen) -} diff --git a/chisel/playground/src/cache/memory/SimpleDualPortRam.scala b/chisel/playground/src/cache/memory/SimpleDualPortRam.scala deleted file mode 100644 index c8767b2..0000000 --- a/chisel/playground/src/cache/memory/SimpleDualPortRam.scala +++ /dev/null @@ -1,96 +0,0 @@ -package cache.memory - -import chisel3._ -import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} -import chisel3.util._ -import cpu.CpuConfig - -/** simple dual port ram, with a port for reading and a port for writing - * - * @param depth - * how many lines there are in the ram - * @param width - * how wide in bits each line is - * @param byteAddressable - * is it byte addressable? - * @param cpuCfg - * the implicit configuration for simulation and elaboration - */ -class SimpleDualPortRam( - depth: Int, - width: Int, - byteAddressable: Boolean -)( - implicit - val cpuConfig: CpuConfig) - extends Module { - require(isPow2(depth)) - require( - width % 8 == 0 || !byteAddressable, - "if memory is byte addressable, then the adderss width must be a multiple of 8" - ) - val waddridth = log2Ceil(depth) - - val io = IO(new Bundle { - val raddr = Input(UInt(waddridth.W)) - val ren = Input(Bool()) - val rdata = Output(UInt(width.W)) - - val waddr = Input(UInt(waddridth.W)) - val wen = Input(Bool()) - val wstrb = Input(UInt((if (byteAddressable) width / 8 else 1).W)) - val wdata = Input(UInt(width.W)) - }) - - if (cpuConfig.build) { - val memory = Module( - new SimpleDualPortRamIP( - wdataidth = width, - byteWriteWidth = if (byteAddressable) 8 else width, - numberOfLines = depth, - waddridth = waddridth - ) - ) - memory.io.clka := clock - memory.io.clkb := clock - memory.io.rstb := reset - - memory.io.addra := io.waddr - memory.io.ena := io.wen - memory.io.dina := io.wdata - memory.io.wea := io.wstrb - - memory.io.addrb := io.raddr - memory.io.enb := io.ren - memory.io.regceb := false.B - io.rdata := memory.io.doutb - } else { - assert( - io.wstrb.orR || !io.wen, - "when write port enable is high, write vector cannot be all 0" - ) - if (byteAddressable) { - val bank = SyncReadMem(depth, Vec(width / 8, UInt(8.W))) - when(io.ren) { - io.rdata := bank.read(io.raddr).asTypeOf(UInt(width.W)) - }.otherwise { - io.rdata := DontCare - } - when(io.wen) { - bank.write(io.waddr, io.wdata.asTypeOf(Vec(width / 8, UInt(8.W))), io.wstrb.asBools) - } - } else { - val bank = SyncReadMem(depth, UInt(width.W)) - - when(io.ren) { - io.rdata := bank.read(io.raddr) - }.otherwise { - io.rdata := 0.U(32.W) - } - - when(io.wen) { - bank.write(io.waddr, io.wdata) - } - } - } -} diff --git a/chisel/playground/src/cache/memory/SimpleDualPortRamIP.scala b/chisel/playground/src/cache/memory/SimpleDualPortRamIP.scala deleted file mode 100644 index b697a00..0000000 --- a/chisel/playground/src/cache/memory/SimpleDualPortRamIP.scala +++ /dev/null @@ -1,68 +0,0 @@ -package cache.memory - -import chisel3._ -import chisel3.util.log2Ceil - -/** simple dual port ram - * - * @param wdataidth - * : width of every data line - * @param byteWriteWidth - * : how many bits to write per mask - * @param numberOfLines - * : how many lines of data are in the ram - * @param waddridth - * : how wide is the request (to cover all lines) - * @param memoryPrimitive - * : should I use auto, block ram or distributed ram - */ -class SimpleDualPortRamIP( - wdataidth: Int = 32, - byteWriteWidth: Int = 8, - numberOfLines: Int, - waddridth: Int, - memoryPrimitive: String = "block", -) extends BlackBox( - Map( - "ADDR_WIDTH_A" -> waddridth, - "ADDR_WIDTH_B" -> waddridth, - "WRITE_DATA_WIDTH_A" -> wdataidth, - "READ_DATA_WIDTH_B" -> wdataidth, - "BYTE_WRITE_WIDTH_A" -> byteWriteWidth, - "CLOCKING_MODE" -> "common_clock", - "READ_LATENCY_B" -> 1, - "MEMORY_SIZE" -> numberOfLines * wdataidth, - "MEMORY_PRIMITIVE" -> memoryPrimitive, - ), - ) { - override def desiredName: String = "xpm_memory_sdpram" - require(waddridth <= 20, "request width should be 1 to 20") - require( - wdataidth - (wdataidth / byteWriteWidth) * byteWriteWidth == 0, - "data width should be a multiple of byte write width", - ) - require( - List("auto", "block", "distributed", "ultra").contains(memoryPrimitive), - "memory primitive should be auto, block ram, dist ram or ultra ram", - ) - require( - waddridth == log2Ceil(numberOfLines), - "request width should be log 2 of number of lines to request all", - ) - val io = IO(new Bundle { - // clock and reset - val clka = Input(Clock()) - val clkb = Input(Clock()) - val rstb = Input(Reset()) - - val addra = Input(UInt(waddridth.W)) - val dina = Input(UInt(wdataidth.W)) - val ena = Input(Bool()) - val wea = Input(UInt((wdataidth / byteWriteWidth).W)) - - val addrb = Input(UInt(waddridth.W)) - val enb = Input(Bool()) - val regceb = Input(Bool()) - val doutb = Output(UInt(wdataidth.W)) - }) -} diff --git a/chisel/playground/src/cache/mmu/Tlb.scala b/chisel/playground/src/cache/mmu/Tlb.scala deleted file mode 100644 index 9822f15..0000000 --- a/chisel/playground/src/cache/mmu/Tlb.scala +++ /dev/null @@ -1,428 +0,0 @@ -package icache.mmu - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ -import cpu.CacheConfig -import cpu.pipeline.execute.CsrTlb -import cpu.CpuConfig - -object AccessType { - def apply() = UInt(2.W) - def fetch = "b00".U - def load = "b01".U - def store = "b10".U -} - -class Tlb_Ptw extends Bundle with HasTlbConst { - val vpn = Decoupled(UInt(vpnLen.W)) - val access_type = Output(AccessType()) - val pte = Flipped(Decoupled(new Bundle { - val access_fault = Bool() - val page_fault = Bool() - val entry = pteBundle - val rmask = UInt(maskLen.W) - })) -} - -class Tlb_ICache extends Bundle with HasTlbConst { - val en = Input(Bool()) - val vaddr = Input(UInt(XLEN.W)) - val complete_single_request = Input(Bool()) - - val uncached = Output(Bool()) - val hit = Output(Bool()) - val ptag = Output(UInt(cacheTagLen.W)) - val paddr = Output(UInt(PADDR_WID.W)) - val access_fault = Output(Bool()) - val page_fault = Output(Bool()) -} - -class Tlb_DCache extends Tlb_ICache { - val access_type = Input(AccessType()) - - // ptw 相关参数 - val ptw = new Tlb_Ptw() - val csr = new CsrTlb() -} - -class Tlb extends Module with HasTlbConst with HasCSRConst { - val io = IO(new Bundle { - val icache = new Tlb_ICache() - val dcache = new Tlb_DCache() - val csr = Flipped(new CsrTlb()) - val sfence_vma = Input(new MouTlb()) - }) - - val satp = io.csr.satp.asTypeOf(satpBundle) - val mstatus = io.csr.mstatus.asTypeOf(new Mstatus) - val imode = io.csr.imode - val dmode = io.csr.dmode - // 当SUM=0时,S模式内存访问U模式可访问的页面(U=1)将出现故障。 - // 当SUM=1时,这些访问是允许的。当基于页面的虚拟内存不生效时,SUM无效。 - // 请注意,虽然SUM通常在不在S模式下执行时被忽略,但当MPRV=1和MPP=S时,SUM有效。 - val sum = mstatus.sum - // 当MXR=0时,只有标记为可读的页面(R=1)的加载才会成功。 - // 当MXR=1时,标记为可读或可执行的页面(R=1或X=1)的加载才会成功。 - // 当基于页面的虚拟内存无效时,MXR无效。 - val mxr = mstatus.mxr - - // 只有当satp.mode为8且当前模式低于M模式时,才启用虚拟内存 - val ivm_enabled = (satp.mode === 8.U) && (imode < ModeM) - val dvm_enabled = (satp.mode === 8.U) && (dmode < ModeM) - - val itlb = RegInit(0.U.asTypeOf(tlbBundle)) - val dtlb = RegInit(0.U.asTypeOf(tlbBundle)) - val tlbl2 = RegInit(VecInit(Seq.fill(cpuConfig.tlbEntries)(0.U.asTypeOf(tlbBundle)))) - - val ivpn = io.icache.vaddr(VADDR_WID - 1, pageOffsetLen) - val dvpn = io.dcache.vaddr(VADDR_WID - 1, pageOffsetLen) - - // 当(VPN一致)且(ASID一致或PTE.G为1时)且(PTE.V为1)时,TLB命中 - val itlbl1_hit = vpnEq(itlb.rmask, ivpn, itlb.vpn) && - (itlb.asid === satp.asid || itlb.flag.g) && - itlb.flag.v - val dtlbl1_hit = vpnEq(dtlb.rmask, dvpn, dtlb.vpn) && - (dtlb.asid === satp.asid || dtlb.flag.g) && - dtlb.flag.v - - val il2_hit_vec = VecInit( - tlbl2.map(tlb => - vpnEq(tlb.rmask, ivpn, tlb.vpn) && - (tlb.asid === satp.asid || tlb.flag.g) && - tlb.flag.v - ) - ) - val dl2_hit_vec = VecInit( - tlbl2.map(tlb => - vpnEq(tlb.rmask, dvpn, tlb.vpn) && - (tlb.asid === satp.asid || tlb.flag.g) && - tlb.flag.v - ) - ) - - val search_l1 :: search_l2 :: search_pte :: search_fault :: Nil = Enum(4) - val immu_state = RegInit(search_l1) - val dmmu_state = RegInit(search_l1) - - // 使用随机的方法替换TLB条目 - val replace_index = new Counter(cpuConfig.tlbEntries) - - val ipage_fault = RegInit(false.B) - val dpage_fault = RegInit(false.B) - val iaccess_fault = RegInit(false.B) - val daccess_fault = RegInit(false.B) - - // ptw的请求标志,0位为指令tlb请求,1位为数据tlb请求 - val req_ptw = WireInit(VecInit(Seq.fill(2)(false.B))) - - val ar_sel_lock = RegInit(false.B) - val ar_sel_val = RegInit(false.B) - // 我们默认优先发送数据tlb的请求 - val choose_icache = Mux(ar_sel_lock, ar_sel_val, req_ptw(0) && !req_ptw(1)) - - when(io.dcache.ptw.vpn.valid) { - when(io.dcache.ptw.vpn.ready) { - ar_sel_lock := false.B - }.otherwise { - ar_sel_lock := true.B - ar_sel_val := choose_icache - } - } - - io.icache.hit := false.B - io.dcache.hit := false.B - io.icache.access_fault := iaccess_fault - io.dcache.access_fault := daccess_fault - io.icache.page_fault := ipage_fault - io.dcache.page_fault := dpage_fault - - // 将ptw模块集成到dcache中,ptw通过dcache的axi进行内存访问 - io.dcache.ptw.vpn.valid := Mux(choose_icache, req_ptw(0), req_ptw(1)) - io.dcache.ptw.access_type := Mux(choose_icache, AccessType.fetch, io.dcache.access_type) - io.dcache.ptw.vpn.bits := Mux(choose_icache, ivpn, dvpn) - io.dcache.ptw.pte.ready := true.B // 恒为true - io.dcache.csr <> io.csr - - def imodeCheck(): Unit = { - switch(imode) { - is(ModeS) { - when(itlb.flag.u && sum === 0.U) { - ipage_fault := true.B - immu_state := search_fault - }.otherwise { - io.icache.hit := true.B - } - } - is(ModeU) { - when(!itlb.flag.u) { - ipage_fault := true.B - immu_state := search_fault - }.otherwise { - io.icache.hit := true.B - } - } - } - } - - def dmodeCheck(): Unit = { - switch(dmode) { - is(ModeS) { - when(dtlb.flag.u && sum === 0.U) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - io.dcache.hit := true.B - } - } - is(ModeU) { - when(!dtlb.flag.u) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - io.dcache.hit := true.B - } - } - } - } - - // --------------------------------------------------- - // ----------------- 指令虚实地址转换 ----------------- - // --------------------------------------------------- - switch(immu_state) { - is(search_l1) { - when(io.icache.en) { - // 在icache实现访问tlb的pma和pmp权限检查 - ipage_fault := false.B - iaccess_fault := false.B - when(!ivm_enabled) { - io.icache.hit := true.B - }.elsewhen(itlbl1_hit) { - // 在这里进行取指需要的所有的权限检查 - // 0. X位检查,只有可执行的页面才能取指 - // 1. M模式,不可能到这里,因为vm_enabled为false - // 2. S模式,如果U位为1,需要检查SUM - // 3. U模式,必须保证U位为1 - io.icache.hit := false.B // 只有权限检查通过后可以置为true - when(!itlb.flag.x) { - ipage_fault := true.B - immu_state := search_fault - }.otherwise { - imodeCheck() - } - }.otherwise { - immu_state := search_l2 - } - } - } - is(search_l2) { - when(il2_hit_vec.asUInt.orR) { - immu_state := search_l1 - itlb := tlbl2(PriorityEncoder(il2_hit_vec)) - }.otherwise { - req_ptw(0) := true.B - when(choose_icache && io.dcache.ptw.vpn.ready) { - immu_state := search_pte - } - } - } - is(search_pte) { - req_ptw(0) := true.B - when(io.dcache.ptw.pte.valid) { - when(io.dcache.ptw.pte.bits.access_fault) { - iaccess_fault := true.B - immu_state := search_fault - }.elsewhen(io.dcache.ptw.pte.bits.page_fault) { - ipage_fault := true.B - immu_state := search_fault - }.otherwise { - // 在内存中找寻到了页表,将其写入TLB - val replace_entry = Wire(tlbBundle) - replace_entry.vpn := ivpn - replace_entry.asid := satp.asid - replace_entry.flag := io.dcache.ptw.pte.bits.entry.flag - replace_entry.ppn := io.dcache.ptw.pte.bits.entry.ppn - replace_entry.rmask := io.dcache.ptw.pte.bits.rmask - tlbl2(replace_index.value) := replace_entry - itlb := replace_entry - replace_index.inc() - immu_state := search_l1 - } - } - } - is(search_fault) { - when(io.icache.complete_single_request) { - ipage_fault := false.B - iaccess_fault := false.B - immu_state := search_l1 - } - } - } - - // --------------------------------------------------- - // ----------------- 数据虚实地址转换 ----------------- - // --------------------------------------------------- - switch(dmmu_state) { - is(search_l1) { - when(io.dcache.en) { - // 在dcache实现访问tlb的pma和pmp权限检查 - dpage_fault := false.B - daccess_fault := false.B - when(!dvm_enabled) { - io.dcache.hit := true.B - }.elsewhen(dtlbl1_hit) { - // 在这里进行取指需要的所有的权限检查 - // 如果是load - // 0. MXR位检查,分类0和1的情况 - // 1. M模式,不可能到这里,因为vm_enabled为false - // 2. S模式,如果U位为1,需要检查SUM - // 3. U模式,必须保证U位为1 - io.dcache.hit := false.B // 只有权限检查通过后可以置为true - switch(io.dcache.access_type) { - is(AccessType.load) { - when(mxr) { - when(!dtlb.flag.r && !dtlb.flag.x) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - dmodeCheck() - } - }.otherwise { - when(!dtlb.flag.r) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - dmodeCheck() - } - } - } - is(AccessType.store) { - when(!dtlb.flag.d) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - when(!dtlb.flag.w) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - dmodeCheck() - } - } - } - } - }.otherwise { - dmmu_state := search_l2 - } - } - } - is(search_l2) { - when(dl2_hit_vec.asUInt.orR) { - dmmu_state := search_l1 - dtlb := tlbl2(PriorityEncoder(dl2_hit_vec)) - }.otherwise { - req_ptw(1) := true.B - when(!choose_icache && io.dcache.ptw.vpn.ready) { - dmmu_state := search_pte - } - } - } - is(search_pte) { - req_ptw(1) := true.B - when(io.dcache.ptw.pte.valid) { - when(io.dcache.ptw.pte.bits.access_fault) { - daccess_fault := true.B - dmmu_state := search_fault - }.elsewhen(io.dcache.ptw.pte.bits.page_fault) { - dpage_fault := true.B - dmmu_state := search_fault - }.otherwise { - // 在内存中找寻到了页表,将其写入TLB - val replace_entry = Wire(tlbBundle) - replace_entry.vpn := dvpn - replace_entry.asid := satp.asid - replace_entry.flag := io.dcache.ptw.pte.bits.entry.flag - replace_entry.ppn := io.dcache.ptw.pte.bits.entry.ppn - replace_entry.rmask := io.dcache.ptw.pte.bits.rmask - tlbl2(replace_index.value) := replace_entry - dtlb := replace_entry - replace_index.inc() - dmmu_state := search_l1 - } - } - } - is(search_fault) { - when(io.dcache.complete_single_request) { - dpage_fault := false.B - daccess_fault := false.B - dmmu_state := search_l1 - } - } - } - - // vpn - val src1 = io.sfence_vma.src_info.src1_data(vpnLen - 1, pageOffsetLen) - // asid - val src2 = io.sfence_vma.src_info.src2_data(asidLen - 1, 0) - when(io.sfence_vma.valid) { - when(!src1.orR && !src2.orR) { - // 将所有tlb的有效位置为0 - itlb.flag.v := false.B - dtlb.flag.v := false.B - for (i <- 0 until cpuConfig.tlbEntries) { - tlbl2(i).flag.v := false.B - } - }.elsewhen(!src1.orR && src2.orR) { - // 将asid一致的且g不为1的tlb的有效位置为0 - when(itlb.asid === src2 && !itlb.flag.g) { - itlb.flag.v := false.B - } - when(dtlb.asid === src2 && !dtlb.flag.g) { - dtlb.flag.v := false.B - } - for (i <- 0 until cpuConfig.tlbEntries) { - when(tlbl2(i).asid === src2 && !tlbl2(i).flag.g) { - tlbl2(i).flag.v := false.B - } - } - }.elsewhen(src1.orR && !src2.orR) { - // 将vpn一致的tlb的有效位置为0 - when(vpnEq(itlb.rmask, src1, itlb.vpn)) { - itlb.flag.v := false.B - } - when(vpnEq(dtlb.rmask, src1, dtlb.vpn)) { - dtlb.flag.v := false.B - } - for (i <- 0 until cpuConfig.tlbEntries) { - when(vpnEq(tlbl2(i).rmask, src1, tlbl2(i).vpn)) { - tlbl2(i).flag.v := false.B - } - } - }.elsewhen(src1.orR && src2.orR) { - // 将asid一致的且vpn一致的tlb的有效位置为0,g为1的除外 - when(itlb.asid === src2 && vpnEq(itlb.rmask, src1, itlb.vpn) && !itlb.flag.g) { - itlb.flag.v := false.B - } - when(dtlb.asid === src2 && vpnEq(dtlb.rmask, src1, dtlb.vpn) && !dtlb.flag.g) { - dtlb.flag.v := false.B - } - for (i <- 0 until cpuConfig.tlbEntries) { - when(tlbl2(i).asid === src2 && vpnEq(tlbl2(i).rmask, src1, tlbl2(i).vpn) && !tlbl2(i).flag.g) { - tlbl2(i).flag.v := false.B - } - } - } - } - - val imasktag = maskTag(itlb.rmask, itlb.ppn, ivpn) - val dmasktag = maskTag(dtlb.rmask, dtlb.ppn, dvpn) - - io.icache.uncached := AddressSpace.isMMIO(io.icache.vaddr) - io.icache.ptag := Mux(ivm_enabled, imasktag, ivpn) - io.icache.paddr := Cat(io.icache.ptag, io.icache.vaddr(pageOffsetLen - 1, 0)) - - io.dcache.uncached := AddressSpace.isMMIO(io.dcache.vaddr) - io.dcache.ptag := Mux(dvm_enabled, dmasktag, dvpn) - io.dcache.paddr := Cat(io.dcache.ptag, io.dcache.vaddr(pageOffsetLen - 1, 0)) - -} diff --git a/chisel/playground/src/defines/StaticBundles.scala b/chisel/playground/src/defines/StaticBundles.scala deleted file mode 100644 index f742f02..0000000 --- a/chisel/playground/src/defines/StaticBundles.scala +++ /dev/null @@ -1,44 +0,0 @@ -package cpu.defines - -import chisel3._ -import chisel3.util._ -import cpu.defines.Const._ -import cpu.CpuConfig - -class SocStatistic extends Bundle { - val csr_count = Output(UInt(32.W)) - val csr_random = Output(UInt(32.W)) - val csr_cause = Output(UInt(32.W)) - val int = Output(Bool()) - val commit = Output(Bool()) -} - -class BranchPredictorUnitStatistic extends Bundle { - val branch = Output(UInt(32.W)) - val success = Output(UInt(32.W)) -} - -class CPUStatistic extends Bundle { - val soc = new SocStatistic() - val bpu = new BranchPredictorUnitStatistic() -} - -class GlobalStatistic extends Bundle { - val cpu = new CPUStatistic() - val cache = new CacheStatistic() -} - -class ICacheStatistic extends Bundle { - val request = Output(UInt(32.W)) - val hit = Output(UInt(32.W)) -} - -class DCacheStatistic extends Bundle { - val request = Output(UInt(32.W)) - val hit = Output(UInt(32.W)) -} - -class CacheStatistic extends Bundle { - val icache = new ICacheStatistic() - val dcache = new DCacheStatistic() -} diff --git a/chisel/playground/src/defines/TlbBundles.scala b/chisel/playground/src/defines/TlbBundles.scala deleted file mode 100644 index 396ab5f..0000000 --- a/chisel/playground/src/defines/TlbBundles.scala +++ /dev/null @@ -1,102 +0,0 @@ -package cpu.defines - -import chisel3._ -import chisel3.util._ -import cpu.defines.Const._ -import cpu.CacheConfig -import cpu.CpuConfig - -trait HasTlbConst extends CoreParameter { - val PAddrBits = PADDR_WID // 32 - val level = 3 - val pageOffsetLen = 12 // 页面大小为4KB,对应的偏移量长度为12位 - val ppn0Len = 9 - val ppn1Len = 9 - val ppn2Len = PAddrBits - pageOffsetLen - ppn0Len - ppn1Len // 2 - val ppnLen = ppn2Len + ppn1Len + ppn0Len // 20 - val vpn2Len = 9 - val vpn1Len = 9 - val vpn0Len = 9 - val vpnLen = vpn2Len + vpn1Len + vpn0Len // 27 - val maskLen = ppn1Len + ppn0Len // 18 - - val satpLen = XLEN - val satpModeLen = 4 - val asidLen = 16 - val flagLen = 8 - - val ptEntryLen = XLEN - val satpResLen = XLEN - ppnLen - satpModeLen - asidLen - val pteResLen = XLEN - ppnLen - 2 - flagLen - - val cacheTagLen = PADDR_WID - pageOffsetLen // 32 - 12 = 20 - require(ppnLen == cacheTagLen) - - def vpnEq(mask: UInt, vpn: UInt, tlbvpn: UInt) = { - val fullmask = Cat(Fill(vpn2Len, true.B), mask) - (vpn & fullmask) === (tlbvpn & fullmask) - } - - def maskTag(mask: UInt, ppn: UInt, vpn: UInt) = { - val fullmask = Cat(Fill(ppn2Len, true.B), mask) - (ppn & fullmask) | (vpn & ~fullmask) - } - - def vpnBundle = new Bundle { - val vpn2 = UInt(vpn2Len.W) - val vpn1 = UInt(vpn1Len.W) - val vpn0 = UInt(vpn0Len.W) - } - - def ppnBundle = new Bundle { - val ppn2 = UInt(ppn2Len.W) - val ppn1 = UInt(ppn1Len.W) - val ppn0 = UInt(ppn0Len.W) - } - - def paddrApply(ppn: UInt, vpnn: UInt): UInt = { - Cat(Cat(ppn, vpnn), 0.U(3.W)) - } - - def pteBundle = new Bundle { - val reserved = UInt(pteResLen.W) - val ppn = UInt(ppnLen.W) - val rsw = UInt(2.W) - val flag = new Bundle { - val d = Bool() - val a = Bool() - val g = Bool() - val u = Bool() - val x = Bool() - val w = Bool() - val r = Bool() - val v = Bool() - } - } - - def satpBundle = new Bundle { - val mode = UInt(satpModeLen.W) - val asid = UInt(asidLen.W) - val res = UInt(satpResLen.W) - val ppn = UInt(ppnLen.W) - } - - def flagBundle = new Bundle { - val d = Bool() - val a = Bool() - val g = Bool() - val u = Bool() - val x = Bool() - val w = Bool() - val r = Bool() - val v = Bool() - } - - def tlbBundle = new Bundle { - val vpn = UInt(vpnLen.W) - val asid = UInt(asidLen.W) - val flag = flagBundle - val ppn = UInt(ppnLen.W) - val rmask = UInt(maskLen.W) - } -} diff --git a/chisel/playground/src/pipeline/decode/Issue.scala b/chisel/playground/src/pipeline/decode/Issue.scala deleted file mode 100644 index d4ce1ef..0000000 --- a/chisel/playground/src/pipeline/decode/Issue.scala +++ /dev/null @@ -1,84 +0,0 @@ -package cpu.pipeline.decode - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ -import cpu.defines.Instructions._ -import cpu.CpuConfig - -class Issue(implicit val cpuConfig: CpuConfig) extends Module with HasCSRConst { - val io = IO(new Bundle { - // 输入 - val allow_to_go = Input(Bool()) - val instFifo = Input(new Bundle { - val empty = Bool() - val almost_empty = Bool() - }) - val decodeInst = Input(Vec(cpuConfig.decoderNum, new Info())) - val execute = Input(Vec(cpuConfig.commitNum, new MemRead())) - // 输出 - val inst1 = Output(new Bundle { - val allow_to_go = Bool() - }) - }) - - if (cpuConfig.decoderNum == 2) { - val inst = io.decodeInst - - // inst buffer是否存有至少2条指令 - val instFifo_invalid = io.instFifo.empty || io.instFifo.almost_empty - - // 结构冲突 - val lsu_conflict = inst.map(_.fusel === FuType.lsu).reduce(_ && _) // 访存单元最大支持1条指令的load和store - val mdu_conflict = inst.map(_.fusel === FuType.mdu).reduce(_ && _) // 乘除单元最大支持1条指令的乘除法 - val csr_conflict = inst.map(_.fusel === FuType.csr).reduce(_ && _) // csr单元最大支持1条指令的读写 - val struct_conflict = lsu_conflict || mdu_conflict || csr_conflict - - // 写后读冲突 - val load_stall = // inst1的源操作数需要经过load得到,但load指令还在exe级未访存 - io.execute(0).is_load && io.execute(0).reg_waddr.orR && - (inst(1).src1_ren && inst(1).src1_raddr === io.execute(0).reg_waddr || - inst(1).src2_ren && inst(1).src2_raddr === io.execute(0).reg_waddr) || - io.execute(1).is_load && io.execute(1).reg_waddr.orR && - (inst(1).src1_ren && inst(1).src1_raddr === io.execute(1).reg_waddr || - inst(1).src2_ren && inst(1).src2_raddr === io.execute(1).reg_waddr) - val raw_reg = // inst1的源操作数是inst0的目的操作数 - inst(0).reg_wen && inst(0).reg_waddr.orR && - (inst(0).reg_waddr === inst(1).src1_raddr && inst(1).src1_ren || - inst(0).reg_waddr === inst(1).src2_raddr && inst(1).src2_ren) - val data_conflict = raw_reg || load_stall - - // bru指令只能在inst0执行 - val is_bru = inst.map(_.fusel === FuType.bru).reduce(_ || _) - - // mou指令会导致流水线清空 - val is_mou = inst.map(_.fusel === FuType.mou).reduce(_ || _) - - // 写satp指令会导致流水线清空 - val write_satp = VecInit( - Seq.tabulate(cpuConfig.commitNum)(i => - inst(i).fusel === FuType.csr && CSROpType.isCSROp(inst(i).op) && inst(i).inst(31, 20) === Satp.U - ) - ).asUInt.orR - - // uret、sret、mret指令会导致流水线清空 - val ret = HasRet(inst(0)) || HasRet(inst(1)) - - // 这些csr相关指令会导致流水线清空 - val is_some_csr_inst = write_satp || ret - - // 下面的情况只进行单发射 - val single_issue = is_mou || is_bru || is_some_csr_inst - - // 指令1是否允许执行 - io.inst1.allow_to_go := - io.allow_to_go && // 指令0允许执行 - !instFifo_invalid && // inst buffer存有至少2条指令 - !struct_conflict && // 无结构冲突 - !data_conflict && // 无写后读冲突 - !single_issue // 非单发射指令 - } else { - io.inst1.allow_to_go := false.B - } -} diff --git a/chisel/playground/src/pipeline/decode/JumpCtrl.scala b/chisel/playground/src/pipeline/decode/JumpCtrl.scala deleted file mode 100644 index 8f14765..0000000 --- a/chisel/playground/src/pipeline/decode/JumpCtrl.scala +++ /dev/null @@ -1,48 +0,0 @@ -package cpu.pipeline.decode - -import chisel3._ -import chisel3.util._ - -import cpu.defines._ -import cpu.defines.Const._ -import cpu.CpuConfig - -class JumpCtrl(implicit val cpuConfig: CpuConfig) extends Module { - val io = IO(new Bundle { - val in = Input(new Bundle { - val pc = UInt(XLEN.W) - val info = new Info() - val src_info = new SrcInfo() - val forward = Vec(cpuConfig.commitNum, new DataForwardToDecodeUnit()) - }) - val out = Output(new Bundle { - val jump_register = Bool() - val jump = Bool() - val jump_target = UInt(XLEN.W) - }) - }) - - val valid = io.in.info.valid - val op = io.in.info.op - val fusel = io.in.info.fusel - val jump_inst = VecInit(BRUOpType.jal).contains(op) && fusel === FuType.bru - val jump_register_inst = VecInit(BRUOpType.jalr).contains(op) && fusel === FuType.bru - io.out.jump := (jump_inst || jump_register_inst && !io.out.jump_register) && valid - if (cpuConfig.decoderNum == 2) { - io.out.jump_register := jump_register_inst && io.in.info.src1_raddr.orR && - ((io.in.forward(0).exe.wen && io.in.info.src1_raddr === io.in.forward(0).exe.waddr) || - (io.in.forward(1).exe.wen && io.in.info.src1_raddr === io.in.forward(1).exe.waddr) || - (io.in.forward(0).mem.wen && io.in.info.src1_raddr === io.in.forward(0).mem.waddr) || - (io.in.forward(1).mem.wen && io.in.info.src1_raddr === io.in.forward(1).mem.waddr)) - - } else { - io.out.jump_register := jump_register_inst && io.in.info.src1_raddr.orR && - ((io.in.forward(0).exe.wen && io.in.info.src1_raddr === io.in.forward(0).exe.waddr) || - (io.in.forward(0).mem.wen && io.in.info.src1_raddr === io.in.forward(0).mem.waddr)) - } - io.out.jump_target := Mux( - jump_inst, - io.in.src_info.src1_data + io.in.src_info.src2_data, - (io.in.src_info.src1_data + io.in.src_info.src2_data) & ~1.U(XLEN.W) - ) -} diff --git a/chisel/playground/src/pipeline/execute/fu/BranchCtrl.scala b/chisel/playground/src/pipeline/execute/fu/BranchCtrl.scala deleted file mode 100644 index bd3113a..0000000 --- a/chisel/playground/src/pipeline/execute/fu/BranchCtrl.scala +++ /dev/null @@ -1,49 +0,0 @@ -package cpu.pipeline.execute - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ - -class BranchCtrl extends Module { - val io = IO(new Bundle { - val in = new Bundle { - val pc = Input(UInt(XLEN.W)) - val info = Input(new Info()) - val src_info = Input(new SrcInfo()) - val pred_branch = Input(Bool()) - val jump_regiser = Input(Bool()) - val branch_target = Input(UInt(XLEN.W)) - } - val out = new Bundle { - val branch = Output(Bool()) - val pred_fail = Output(Bool()) - val target = Output(UInt(XLEN.W)) - } - }) - val valid = - io.in.info.fusel === FuType.bru && BRUOpType.isBranch(io.in.info.op) && io.in.info.valid - val src1 = io.in.src_info.src1_data - val src2 = io.in.src_info.src2_data - val op = io.in.info.op - val is_sub = !BRUOpType.isAdd(op) - val adder = (src1 +& (src2 ^ Fill(XLEN, is_sub))) + is_sub - val xor = src1 ^ src2 - val sltu = !adder(XLEN) - val slt = xor(XLEN - 1) ^ sltu - val table = List( - BRUOpType.getBranchType(BRUOpType.beq) -> !xor.orR, - BRUOpType.getBranchType(BRUOpType.blt) -> slt, - BRUOpType.getBranchType(BRUOpType.bltu) -> sltu - ) - io.out.pred_fail := io.in.pred_branch =/= io.out.branch - io.out.branch := - (LookupTree(BRUOpType.getBranchType(op), table) ^ BRUOpType.isBranchInvert(op)) & valid - io.out.target := Mux1H( - Seq( - (io.out.pred_fail && io.out.branch) -> io.in.branch_target, - (io.out.pred_fail && !io.out.branch) -> (io.in.pc + 4.U), - (io.in.jump_regiser) -> ((src1 + src2) & ~1.U(XLEN.W)) - ) - ) -} diff --git a/chisel/playground/src/pipeline/fetch/BranchPredictorUnit.scala b/chisel/playground/src/pipeline/fetch/BranchPredictorUnit.scala deleted file mode 100644 index e019e85..0000000 --- a/chisel/playground/src/pipeline/fetch/BranchPredictorUnit.scala +++ /dev/null @@ -1,150 +0,0 @@ -package cpu.pipeline.fetch - -import chisel3._ -import chisel3.util._ -import cpu.defines.Const._ -import cpu._ -import cpu.pipeline.decode.Src12Read -import cpu.defines.BRUOpType -import cpu.defines.FuOpType -import cpu.defines.FuType -import cpu.defines.SignedExtend -import cpu.pipeline.decode.DecoderBranchPredictorUnit -import pipeline.decode.{DecoderBranchPredictorUnit, Src12Read} - -class ExecuteUnitBranchPredictor extends Bundle { - val bpuConfig = new BranchPredictorConfig() - val pc = Output(UInt(XLEN.W)) - val update_pht_index = Output(UInt(bpuConfig.phtDepth.W)) - val branch_inst = Output(Bool()) - val branch = Output(Bool()) -} - -class BranchPredictorIO(implicit cpuConfig: CpuConfig) extends Bundle { - val bpuConfig = new BranchPredictorConfig() - val decode = Flipped(new DecoderBranchPredictorUnit()) - - val instBuffer = new Bundle { - val pc = Input(Vec(cpuConfig.instFetchNum, UInt(XLEN.W))) - val pht_index = Output(Vec(cpuConfig.instFetchNum, UInt(bpuConfig.phtDepth.W))) - } - - val execute = Flipped(new ExecuteUnitBranchPredictor()) -} - -class BranchPredictorUnit(implicit cpuConfig: CpuConfig) extends Module { - val io = IO(new BranchPredictorIO()) - - if (cpuConfig.branchPredictor == "adaptive") { - val adaptive_predictor = Module(new AdaptiveTwoLevelPredictor()) - io <> adaptive_predictor.io - } - - if (cpuConfig.branchPredictor == "global") { - val global_predictor = Module(new GlobalBranchPredictor()) - io <> global_predictor.io - } -} - -class GlobalBranchPredictor( - GHR_DEPTH: Int = 4, // 可以记录的历史记录个数 - PC_HASH_WID: Int = 4, // 取得PC的宽度 - PHT_DEPTH: Int = 6, // 可以记录的历史个数 - BHT_DEPTH: Int = 4 // 取得PC的宽度 -)( - implicit - cpuConfig: CpuConfig) - extends Module { - val io = IO(new BranchPredictorIO()) - - val strongly_not_taken :: weakly_not_taken :: weakly_taken :: strongly_taken :: Nil = Enum(4) - - val imm = io.decode.info.imm - - io.decode.branch_inst := io.decode.info.valid && - FuType.bru === io.decode.info.fusel && BRUOpType.isBranch(io.decode.info.op) - io.decode.target := io.decode.pc + imm - // 局部预测模式 - - val bht = RegInit(VecInit(Seq.fill(1 << BHT_DEPTH)(0.U(PHT_DEPTH.W)))) - val pht = RegInit(VecInit(Seq.fill(1 << PHT_DEPTH)(strongly_taken))) - val bht_index = io.decode.pc(1 + BHT_DEPTH, 2) - val pht_index = bht(bht_index) - - io.decode.branch := - io.decode.branch_inst && (pht(pht_index) === weakly_taken || pht(pht_index) === strongly_taken) - val update_bht_index = io.execute.pc(1 + BHT_DEPTH, 2) - val update_pht_index = bht(update_bht_index) - - when(io.execute.branch_inst) { - bht(update_bht_index) := Cat(bht(update_bht_index)(PHT_DEPTH - 2, 0), io.execute.branch) - switch(pht(update_pht_index)) { - is(strongly_not_taken) { - pht(update_pht_index) := Mux(io.execute.branch, weakly_not_taken, strongly_not_taken) - } - is(weakly_not_taken) { - pht(update_pht_index) := Mux(io.execute.branch, weakly_taken, strongly_not_taken) - } - is(weakly_taken) { - pht(update_pht_index) := Mux(io.execute.branch, strongly_taken, weakly_not_taken) - } - is(strongly_taken) { - pht(update_pht_index) := Mux(io.execute.branch, strongly_taken, weakly_taken) - } - } - } - -} - -class AdaptiveTwoLevelPredictor( -)( - implicit - cpuConfig: CpuConfig) - extends Module { - val bpuConfig = new BranchPredictorConfig() - val PHT_DEPTH = bpuConfig.phtDepth - val BHT_DEPTH = bpuConfig.bhtDepth - val io = IO(new BranchPredictorIO()) - - val strongly_not_taken :: weakly_not_taken :: weakly_taken :: strongly_taken :: Nil = Enum(4) - - val imm = io.decode.info.imm - - io.decode.branch_inst := io.decode.info.valid && - FuType.bru === io.decode.info.fusel && BRUOpType.isBranch(io.decode.info.op) - io.decode.target := io.decode.pc + imm - - val bht = RegInit(VecInit(Seq.fill(1 << BHT_DEPTH)(0.U(PHT_DEPTH.W)))) - val pht = RegInit(VecInit(Seq.fill(1 << PHT_DEPTH)(strongly_taken))) - val pht_index = io.decode.pht_index - - for (i <- 0 until cpuConfig.instFetchNum) { - io.instBuffer.pht_index(i) := bht(io.instBuffer.pc(i)(1 + BHT_DEPTH, 2)) - } - - io.decode.branch := - io.decode.branch_inst && (pht(pht_index) === weakly_taken || pht(pht_index) === strongly_taken) - io.decode.update_pht_index := bht(io.decode.pc(1 + BHT_DEPTH, 2)) - - val update_bht_index = io.execute.pc(1 + BHT_DEPTH, 2) - val update_pht_index = io.execute.update_pht_index - - when(io.execute.branch_inst) { - bht(update_bht_index) := Cat(bht(update_bht_index)(PHT_DEPTH - 2, 0), io.execute.branch) - switch(pht(update_pht_index)) { - is(strongly_not_taken) { - pht(update_pht_index) := Mux(io.execute.branch, weakly_not_taken, strongly_not_taken) - } - is(weakly_not_taken) { - pht(update_pht_index) := Mux(io.execute.branch, weakly_taken, strongly_not_taken) - } - is(weakly_taken) { - pht(update_pht_index) := Mux(io.execute.branch, strongly_taken, weakly_not_taken) - } - is(strongly_taken) { - pht(update_pht_index) := Mux(io.execute.branch, strongly_taken, weakly_taken) - } - } - } - -} diff --git a/chisel/playground/src/pipeline/fetch/InstFifo.scala b/chisel/playground/src/pipeline/fetch/InstFifo.scala deleted file mode 100644 index 8cd0bfe..0000000 --- a/chisel/playground/src/pipeline/fetch/InstFifo.scala +++ /dev/null @@ -1,102 +0,0 @@ -package cpu.pipeline.fetch - -import chisel3._ -import chisel3.util._ -import cpu.defines.Const._ -import cpu.{BranchPredictorConfig, CpuConfig} -import cpu.pipeline.decode.DecodeUnitInstFifo - -class IfIdData extends Bundle { - val bpuConfig = new BranchPredictorConfig() - val inst = UInt(XLEN.W) - val pht_index = UInt(bpuConfig.phtDepth.W) - val addr_misaligned = Bool() - val access_fault = Bool() - val page_fault = Bool() - val pc = UInt(XLEN.W) -} - -class InstFifo(implicit val cpuConfig: CpuConfig) extends Module { - val io = IO(new Bundle { - val do_flush = Input(Bool()) - - val wen = Input(Vec(cpuConfig.instFetchNum, Bool())) - val write = Input(Vec(cpuConfig.instFetchNum, new IfIdData())) - val full = Output(Bool()) - - val decoderUint = Flipped(new DecodeUnitInstFifo()) - }) - // fifo buffer - val buffer = RegInit(VecInit(Seq.fill(cpuConfig.instFifoDepth)(0.U.asTypeOf(new IfIdData())))) - - // fifo ptr - val enq_ptr = RegInit(0.U(log2Ceil(cpuConfig.instFifoDepth).W)) - val deq_ptr = RegInit(0.U(log2Ceil(cpuConfig.instFifoDepth).W)) - val count = RegInit(0.U(log2Ceil(cpuConfig.instFifoDepth).W)) - - // config.instFifoDepth - 1 is the last element, config.instFifoDepth - 2 is the last second element - // the second last element's valid decide whether the fifo is full - - val full = count >= (cpuConfig.instFifoDepth - cpuConfig.instFetchNum).U - val empty = count === 0.U - val almost_empty = count === 1.U - - io.full := full - io.decoderUint.info.empty := empty - io.decoderUint.info.almost_empty := almost_empty - - // * deq * // - io.decoderUint.inst(0) := MuxCase( - buffer(deq_ptr), - Seq( - empty -> 0.U.asTypeOf(new IfIdData()), - almost_empty -> buffer(deq_ptr) - ) - ) - - io.decoderUint.inst(1) := MuxCase( - buffer(deq_ptr + 1.U), - Seq( - (empty || almost_empty) -> 0.U.asTypeOf(new IfIdData()) - ) - ) - - val deq_num = MuxCase( - 0.U, - Seq( - (empty) -> 0.U, - io.decoderUint.allow_to_go(1) -> 2.U, - io.decoderUint.allow_to_go(0) -> 1.U - ) - ) - - when(io.do_flush) { - deq_ptr := 0.U - }.otherwise { - deq_ptr := deq_ptr + deq_num - } - - // * enq * // - val enq_num = Wire(UInt(log2Ceil(cpuConfig.instFetchNum + 1).W)) - - for (i <- 0 until cpuConfig.instFetchNum) { - when(io.wen(i)) { - buffer(enq_ptr + i.U) := io.write(i) - } - } - - when(io.do_flush) { - enq_ptr := 0.U - }.otherwise { - enq_ptr := enq_ptr + enq_num - } - - enq_num := 0.U - for (i <- 0 until cpuConfig.instFetchNum) { - when(io.wen(i)) { - enq_num := (i + 1).U - } - } - - count := Mux(io.do_flush, 0.U, count + enq_num + cpuConfig.instFifoDepth.U - deq_num) -} diff --git a/chisel/playground/src/pipeline/memory/Lsu.scala b/chisel/playground/src/pipeline/memory/Lsu.scala deleted file mode 100644 index 2b0e466..0000000 --- a/chisel/playground/src/pipeline/memory/Lsu.scala +++ /dev/null @@ -1,210 +0,0 @@ -package cpu.pipeline.memory - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ -import cpu.CpuConfig -import chisel3.util.experimental.BoringUtils - -class Lsu_DataMemory extends Bundle { - val in = Input(new Bundle { - val access_fault = Bool() - val page_fault = Bool() - val ready = Bool() - val rdata = UInt(XLEN.W) - }) - val out = Output(new Bundle { - val en = Bool() - val rlen = UInt(AXI_LEN_WID.W) - val wen = Bool() - val wstrb = UInt(AXI_STRB_WID.W) - val addr = UInt(XLEN.W) - val wdata = UInt(XLEN.W) - }) -} - -class Lsu_MemoryUnit extends Bundle { - val in = Input(new Bundle { - val mem_en = Bool() - val info = new Info() - val src_info = new SrcInfo() - val ex = new ExceptionInfo() - - val lr = Bool() - val lr_addr = UInt(XLEN.W) - - val allow_to_go = Bool() - }) - val out = Output(new Bundle { - val ready = Bool() - val rdata = UInt(XLEN.W) - val ex = new ExceptionInfo() - // 用于指示dcache完成一次请求 - val complete_single_request = Bool() - - val lr_wen = Bool() - val lr_wbit = Bool() - val lr_waddr = UInt(XLEN.W) - }) -} - -class Lsu(implicit val cpuConfig: CpuConfig) extends Module { - val io = IO(new Bundle { - val memoryUnit = new Lsu_MemoryUnit() - val dataMemory = new Lsu_DataMemory() - }) - - val atomAlu = Module(new AtomAlu()).io - val lsExecute = Module(new LsExecute()).io - - val valid = io.memoryUnit.in.mem_en - val src1 = io.memoryUnit.in.src_info.src1_data - val src2 = io.memoryUnit.in.src_info.src2_data - val imm = io.memoryUnit.in.info.imm - val func = io.memoryUnit.in.info.op - val inst = io.memoryUnit.in.info.inst - - val store_req = valid & LSUOpType.isStore(func) - val load_req = valid & LSUOpType.isLoad(func) - val atom_req = valid & LSUOpType.isAtom(func) - val amo_req = valid & LSUOpType.isAMO(func) - val lr_req = valid & LSUOpType.isLR(func) - val sc_req = valid & LSUOpType.isSC(func) - - val funct3 = inst(14, 12) - val atom_d = funct3(0) - - // Atom LR/SC Control Bits - val lr = WireInit(Bool(), false.B) - val lr_addr = WireInit(UInt(XLEN.W), DontCare) - io.memoryUnit.out.lr_wen := io.memoryUnit.out.ready && (lr_req || sc_req) - io.memoryUnit.out.lr_wbit := lr_req - io.memoryUnit.out.lr_waddr := src1 - lr := io.memoryUnit.in.lr - lr_addr := io.memoryUnit.in.lr_addr - - val s_idle :: s_sc :: s_amo_a :: s_amo_s :: Nil = Enum(4) - - val state = RegInit(s_idle) - val atom_wdata = Reg(UInt(XLEN.W)) - val atom_rdata = Reg(UInt(XLEN.W)) - atomAlu.in.rdata := atom_wdata - atomAlu.in.src2 := src2 - atomAlu.in.info := io.memoryUnit.in.info - - val sc_invalid = (src1 =/= lr_addr || !lr) && sc_req - - lsExecute.in.info := DontCare - lsExecute.in.mem_addr := DontCare - lsExecute.in.mem_en := false.B - lsExecute.in.wdata := DontCare - io.memoryUnit.out.ready := false.B - - val allow_to_go = io.memoryUnit.in.allow_to_go - val complete_single_request = Wire(Bool()) - // 只有amo操作时该信号才发挥作用 - complete_single_request := false.B - - io.memoryUnit.out.complete_single_request := complete_single_request - - switch(state) { - is(s_idle) { // 0 - lsExecute.in.mem_en := io.memoryUnit.in.mem_en && !atom_req - lsExecute.in.mem_addr := src1 + imm - lsExecute.in.info.op := func - lsExecute.in.wdata := src2 - io.memoryUnit.out.ready := lsExecute.out.ready || sc_invalid - when(amo_req) { - lsExecute.in.mem_en := true.B - lsExecute.in.mem_addr := src1 - lsExecute.in.info.op := Mux(atom_d, LSUOpType.ld, LSUOpType.lw) - lsExecute.in.wdata := DontCare - io.memoryUnit.out.ready := false.B - when(lsExecute.out.ready) { - state := s_amo_a; - // 告诉dcache已经完成一次访存操作,可以进入下一次访存 - complete_single_request := true.B - } - atom_wdata := lsExecute.out.rdata - atom_rdata := lsExecute.out.rdata - } - when(lr_req) { - lsExecute.in.mem_en := true.B - lsExecute.in.mem_addr := src1 - lsExecute.in.info.op := Mux(atom_d, LSUOpType.ld, LSUOpType.lw) - lsExecute.in.wdata := DontCare - io.memoryUnit.out.ready := lsExecute.out.ready - } - when(sc_req) { state := Mux(sc_invalid, s_idle, s_sc) } - } - - is(s_sc) { // 1 - lsExecute.in.mem_en := true.B - lsExecute.in.mem_addr := src1 - lsExecute.in.info.op := Mux(atom_d, LSUOpType.sd, LSUOpType.sw) - lsExecute.in.wdata := src2 - io.memoryUnit.out.ready := lsExecute.out.ready - when(allow_to_go) { - state := s_idle - } - } - - is(s_amo_a) { // 2 - lsExecute.in.mem_en := false.B - lsExecute.in.mem_addr := DontCare - lsExecute.in.info.op := DontCare - lsExecute.in.wdata := DontCare - io.memoryUnit.out.ready := false.B - state := s_amo_s - atom_wdata := atomAlu.out.result - } - - is(s_amo_s) { // 3 - lsExecute.in.mem_en := true.B - lsExecute.in.mem_addr := src1 - lsExecute.in.info.op := Mux(atom_d, LSUOpType.sd, LSUOpType.sw) - lsExecute.in.wdata := atom_wdata - io.memoryUnit.out.ready := lsExecute.out.ready - when(allow_to_go) { - state := s_idle - } - } - } - - when( - lsExecute.out.addr_misaligned || - lsExecute.out.access_fault || - lsExecute.out.page_fault - ) { - state := s_idle - io.memoryUnit.out.ready := true.B - complete_single_request := false.B // 发生例外时应该由ctrl的allow to go控制 - } - - io.dataMemory <> lsExecute.dataMemory - - io.memoryUnit.out.ex := io.memoryUnit.in.ex - io.memoryUnit.out.ex.exception(loadAddrMisaligned) := (load_req || lr_req) && lsExecute.out.addr_misaligned - io.memoryUnit.out.ex.exception(loadAccessFault) := (load_req || lr_req) && lsExecute.out.access_fault - io.memoryUnit.out.ex.exception(loadPageFault) := (load_req || lr_req) && lsExecute.out.page_fault - io.memoryUnit.out.ex - .exception(storeAddrMisaligned) := (store_req || sc_req || amo_req) && lsExecute.out.addr_misaligned - io.memoryUnit.out.ex.exception(storeAccessFault) := (store_req || sc_req || amo_req) && lsExecute.out.addr_misaligned - io.memoryUnit.out.ex.exception(storePageFault) := (store_req || sc_req || amo_req) && lsExecute.out.page_fault - - io.memoryUnit.out.ex.tval(loadAddrMisaligned) := io.dataMemory.out.addr - io.memoryUnit.out.ex.tval(loadAccessFault) := io.dataMemory.out.addr - io.memoryUnit.out.ex.tval(loadPageFault) := io.dataMemory.out.addr - io.memoryUnit.out.ex.tval(storeAddrMisaligned) := io.dataMemory.out.addr - io.memoryUnit.out.ex.tval(storeAccessFault) := io.dataMemory.out.addr - io.memoryUnit.out.ex.tval(storePageFault) := io.dataMemory.out.addr - - io.memoryUnit.out.rdata := MuxCase( - lsExecute.out.rdata, - Seq( - (sc_req) -> sc_invalid, - (amo_req) -> atom_rdata - ) - ) -} diff --git a/chisel/playground/src/pipeline/memory/Mou.scala b/chisel/playground/src/pipeline/memory/Mou.scala deleted file mode 100644 index cc7711d..0000000 --- a/chisel/playground/src/pipeline/memory/Mou.scala +++ /dev/null @@ -1,31 +0,0 @@ -package cpu.pipeline.memory - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ - -class Mou extends Module { - val io = IO(new Bundle { - val in = Input(new Bundle { - val info = new Info() - val pc = UInt(XLEN.W) - }) - val out = Output(new Bundle { - val flush = Bool() - val fence_i = Bool() - val sfence_vma = Bool() - val target = UInt(XLEN.W) - }) - }) - - val valid = io.in.info.valid && io.in.info.fusel === FuType.mou - val fence_i = valid && io.in.info.op === MOUOpType.fencei - val sfence_vma = valid && io.in.info.op === MOUOpType.sfence_vma - - io.out.flush := valid - io.out.fence_i := fence_i - io.out.sfence_vma := sfence_vma - io.out.target := io.in.pc + 4.U - -} diff --git a/chisel/playground/src/pipeline/memory/lsu/AtomAlu.scala b/chisel/playground/src/pipeline/memory/lsu/AtomAlu.scala deleted file mode 100644 index 2206b13..0000000 --- a/chisel/playground/src/pipeline/memory/lsu/AtomAlu.scala +++ /dev/null @@ -1,48 +0,0 @@ -package cpu.pipeline.memory - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ -import cpu.CpuConfig - -class AtomAlu extends Module { - val io = IO(new Bundle { - val in = Input(new Bundle { - val rdata = Input(UInt(XLEN.W)) // load data - val src2 = Input(UInt(XLEN.W)) // reg data - val info = new Info() - }) - val out = Output(new Bundle { - val result = Output(UInt(XLEN.W)) - }) - }) - - val src1 = io.in.rdata - val src2 = io.in.src2 - val op = io.in.info.op - val is_sub = !LSUOpType.isAdd(op) - val sum = (src1 +& (src2 ^ Fill(XLEN, is_sub))) + is_sub - val oxr = src1 ^ src2 - val sltu = !sum(XLEN) - val slt = oxr(XLEN - 1) ^ sltu - val is_word = !io.in.info.inst(12) - - val res = LookupTreeDefault( - op(5, 0), - sum, - List( - LSUOpType.amoswap -> src2, - LSUOpType.amoadd -> sum, - LSUOpType.amoxor -> oxr, - LSUOpType.amoand -> (src1 & src2), - LSUOpType.amoor -> (src1 | src2), - LSUOpType.amomin -> Mux(slt(0), src1, src2), - LSUOpType.amomax -> Mux(slt(0), src2, src1), - LSUOpType.amominu -> Mux(sltu(0), src1, src2), - LSUOpType.amomaxu -> Mux(sltu(0), src2, src1) - ) - ) - - io.out.result := Mux(is_word, SignedExtend(res(31, 0), 64), res(XLEN - 1, 0)) -} diff --git a/chisel/playground/src/pipeline/memory/lsu/LsExecute.scala b/chisel/playground/src/pipeline/memory/lsu/LsExecute.scala deleted file mode 100644 index dbda744..0000000 --- a/chisel/playground/src/pipeline/memory/lsu/LsExecute.scala +++ /dev/null @@ -1,143 +0,0 @@ -package cpu.pipeline.memory - -import chisel3._ -import chisel3.util._ -import cpu.defines._ -import cpu.defines.Const._ -import cpu.CpuConfig - -class LsExecute extends Module { - val io = IO(new Bundle { - val dataMemory = new Lsu_DataMemory() - val in = Input(new Bundle { - val mem_en = Bool() - val mem_addr = UInt(XLEN.W) - val wdata = UInt(XLEN.W) - val info = new Info() - }) - val out = Output(new Bundle { - val addr_misaligned = Bool() - val access_fault = Bool() - val page_fault = Bool() - val rdata = UInt(XLEN.W) - val ready = Bool() - }) - }) - - def genWmask(addr: UInt, sizeEncode: UInt): UInt = { - LookupTree( - sizeEncode, - List( - "b00".U -> 0x1.U, //0001 << addr(2:0) - "b01".U -> 0x3.U, //0011 - "b10".U -> 0xf.U, //1111 - "b11".U -> 0xff.U //11111111 - ) - ) << addr(2, 0) - } - def genWdata(data: UInt, sizeEncode: UInt): UInt = { - LookupTree( - sizeEncode, - List( - "b00".U -> Fill(8, data(7, 0)), - "b01".U -> Fill(4, data(15, 0)), - "b10".U -> Fill(2, data(31, 0)), - "b11".U -> data - ) - ) - } - - def genWmask32(addr: UInt, sizeEncode: UInt): UInt = { - LookupTree( - sizeEncode, - List( - "b00".U -> 0x1.U, //0001 << addr(1:0) - "b01".U -> 0x3.U, //0011 - "b10".U -> 0xf.U //1111 - ) - ) << addr(1, 0) - } - def genWdata32(data: UInt, sizeEncode: UInt): UInt = { - LookupTree( - sizeEncode, - List( - "b00".U -> Fill(4, data(7, 0)), - "b01".U -> Fill(2, data(15, 0)), - "b10".U -> data - ) - ) - } - - val valid = io.in.mem_en - val addr = io.in.mem_addr - val op = io.in.info.op - - val is_store = valid && LSUOpType.isStore(op) - val partial_load = !is_store && (op =/= LSUOpType.ld) - - val size = op(1, 0) - val req_addr = if (XLEN == 32) SignedExtend(addr, XLEN) else addr - val req_wdata = if (XLEN == 32) genWdata32(io.in.wdata, size) else genWdata(io.in.wdata, size) - val req_wmask = if (XLEN == 32) genWmask32(addr, size) else genWmask(addr, size) - - val rdata = io.dataMemory.in.rdata - val access_fault = io.dataMemory.in.access_fault - val page_fault = io.dataMemory.in.page_fault - - val rdata64 = LookupTree( - addr(2, 0), - List( - "b000".U -> rdata(63, 0), - "b001".U -> rdata(63, 8), - "b010".U -> rdata(63, 16), - "b011".U -> rdata(63, 24), - "b100".U -> rdata(63, 32), - "b101".U -> rdata(63, 40), - "b110".U -> rdata(63, 48), - "b111".U -> rdata(63, 56) - ) - ) - val rdata32 = LookupTree( - addr(1, 0), - List( - "b00".U -> rdata(31, 0), - "b01".U -> rdata(31, 8), - "b10".U -> rdata(31, 16), - "b11".U -> rdata(31, 24) - ) - ) - val rdata_result = if (XLEN == 32) rdata32 else rdata64 - val rdata_partial_result = LookupTree( - op, - List( - LSUOpType.lb -> SignedExtend(rdata_result(7, 0), XLEN), - LSUOpType.lh -> SignedExtend(rdata_result(15, 0), XLEN), - LSUOpType.lw -> SignedExtend(rdata_result(31, 0), XLEN), - LSUOpType.lbu -> ZeroExtend(rdata_result(7, 0), XLEN), - LSUOpType.lhu -> ZeroExtend(rdata_result(15, 0), XLEN), - LSUOpType.lwu -> ZeroExtend(rdata_result(31, 0), XLEN) - ) - ) - val addr_aligned = LookupTree( - op(1, 0), - List( - "b00".U -> true.B, //b - "b01".U -> (addr(0) === 0.U), //h - "b10".U -> (addr(1, 0) === 0.U), //w - "b11".U -> (addr(2, 0) === 0.U) //d - ) - ) - - io.dataMemory.out.en := valid && !io.out.addr_misaligned - io.dataMemory.out.rlen := size - io.dataMemory.out.wen := is_store - io.dataMemory.out.wstrb := req_wmask - io.dataMemory.out.addr := req_addr - io.dataMemory.out.wdata := req_wdata - - io.out.ready := io.dataMemory.in.ready && io.dataMemory.out.en - io.out.rdata := Mux(partial_load, rdata_partial_result, rdata_result) - io.out.addr_misaligned := valid && !addr_aligned - io.out.access_fault := valid && access_fault - io.out.page_fault := valid && page_fault -} diff --git a/chisel/playground/src/pipeline/writeback/CommitBuffer.scala b/chisel/playground/src/pipeline/writeback/CommitBuffer.scala deleted file mode 100644 index a848c93..0000000 --- a/chisel/playground/src/pipeline/writeback/CommitBuffer.scala +++ /dev/null @@ -1,80 +0,0 @@ -package cpu.pipeline.writeback - -import chisel3._ -import chisel3.util._ -import cpu.defines.DEBUG - -class CommitBuffer( - depth: Int = 128) - extends Module { - val io = IO(new Bundle { - val flush = Input(Bool()) - val enq = Flipped(Vec(2, new DEBUG())) - val deq = new DEBUG() - }) - - val ram = RegInit(VecInit(Seq.fill(depth)(0.U.asTypeOf(new DEBUG())))) - val enq_ptr = RegInit(0.U(log2Ceil(depth).W)) - val deq_ptr = RegInit(0.U(log2Ceil(depth).W)) - val maybe_full = RegInit(false.B) - val ptr_match = enq_ptr === deq_ptr - val empty = ptr_match && !maybe_full - val full = ptr_match && maybe_full - val do_enq = Wire(Vec(2, Bool())) - val do_deq = WireDefault(io.deq.wb_rf_wen.orR) - - for { i <- 0 until 2 } { - do_enq(i) := io.enq(i).wb_rf_wen.orR - } - - val next_enq_ptr = MuxCase( - enq_ptr, - Seq( - io.flush -> 0.U, - (do_enq(0) && do_enq(1)) -> (enq_ptr + 2.U), - (do_enq(0) || do_enq(1)) -> (enq_ptr + 1.U) - ) - ) - - when(do_enq(0)) { - ram(enq_ptr) := io.enq(0) - } - - val enq1_ptr = Mux(do_enq(0), enq_ptr + 1.U, enq_ptr) - when(do_enq(1)) { - ram(enq1_ptr) := io.enq(1) - } - - val next_deq_ptr = - Mux(do_deq, deq_ptr + 1.U, deq_ptr) - - when(do_enq(0) =/= do_deq) { - maybe_full := do_enq(0) - } - - when(do_enq(1)) { - maybe_full := do_enq(1) - } - - when(io.flush) { - enq_ptr := 0.U - deq_ptr := 0.U - maybe_full := false.B - }.otherwise { - enq_ptr := next_enq_ptr - deq_ptr := next_deq_ptr - } - - when(do_deq) { - ram(deq_ptr).wb_rf_wen := 0.U - } - - when(empty) { - do_deq := false.B - io.deq := DontCare - io.deq.wb_rf_wen := 0.U - }.otherwise { - io.deq := ram(deq_ptr) - } - -}