增加puamips的cache文件

This commit is contained in:
Liphen 2023-12-19 15:08:24 +08:00
parent 41da1f4c3e
commit 3134b79c54
6 changed files with 351 additions and 0 deletions

View File

@ -26,3 +26,29 @@ case class CpuConfig(
case class BranchPredictorConfig(
val bhtDepth: Int = 5,
val phtDepth: Int = 6)
case class CacheConfig(
nway: Int = 2, // 路数
nbank: Int = 8, // bank数
nset: Int,
bankWidth: Int // bytes per bank
) {
val config = CpuConfig()
val indexWidth = log2Ceil(nset) // 6
val bankIndexWidth = log2Ceil(nbank) // 3
val bankOffsetWidth = log2Ceil(bankWidth) // 3
val offsetWidth = bankIndexWidth + bankOffsetWidth // 6
val tagWidth = 32 - indexWidth - offsetWidth // 20
val tagvWidth = tagWidth + 1 // 21
val bankWidthBits = bankWidth * 8 // 64
val burstSize = 16
val ninst = config.instFetchNum // TODO:改成可随意修改的参数
require(isPow2(nset))
require(isPow2(nway))
require(isPow2(nbank))
require(isPow2(bankWidth))
require(
tagWidth + indexWidth + bankIndexWidth + bankOffsetWidth == 32,
"basic request calculation"
)
}

View File

@ -0,0 +1,64 @@
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 config: 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 (config.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)
}
}
}

View File

@ -0,0 +1,65 @@
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))
})
}

View File

@ -0,0 +1,37 @@
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.nset * cacheConfig.nbank).W))
val data = Output(gen)
}
class WriteOnlyPort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle {
val addr = Input(UInt(log2Ceil(cacheConfig.nset * 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.nset * cacheConfig.nbank).W))
val en = Input(UInt(cacheConfig.bankWidth.W))
val data = Input(gen)
}
class ReadWritePort[+T <: Data](gen: T)(implicit cacheConfig: CacheConfig) extends Bundle {
val addr = Input(UInt(log2Ceil(cacheConfig.nset * 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.nset * cacheConfig.nbank).W))
val writeMask = Input(UInt(cacheConfig.bankWidth.W))
val wdata = Input(gen)
val rdata = Output(gen)
}

View File

@ -0,0 +1,91 @@
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 config: 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 (config.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(io.raddr).asTypeOf(io.rdata)
}.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)
}
}
}
}

View File

@ -0,0 +1,68 @@
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))
})
}