未验证 提交 0e8472d1 编写于 作者: Y Yinan Xu 提交者: GitHub

Merge branch 'master' into new-lbuf

......@@ -21,26 +21,13 @@ jobs:
run: |
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
echo ::set-env name=RVTEST_HOME::/home/ci-runner/xsenv/riscv-tests
echo ::set-env name=AM_HOME::/home/ci-runner/xsenv/nexus-am
- name: Build EMU
run:
make ./build/emu SIM_ARGS=--disable-log EMU_THREADS=16 NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
cputest:
runs-on: self-hosted
name: Run cputest
needs: [build-emu]
steps:
- name: Set env
run: |
echo ::set-env name=AM_HOME::/home/ci-runner/xsenv/nexus-am
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
- name: Run cputest
run: |
echo $AM_HOME
echo $NEMU_HOME
echo $NOOP_HOME
CPU_TEST_DIR=$AM_HOME/tests/cputest
echo $CPU_TEST_DIR
ret=0
......@@ -56,38 +43,9 @@ jobs:
fi
done
exit $ret
microbench:
runs-on: self-hosted
name: Run microbench
needs: [build-emu]
steps:
- name: Set env
- name: Run riscv-tests
run: |
echo ::set-env name=AM_HOME::/home/ci-runner/xsenv/nexus-am
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um SUITES+=rv64ua NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run 2> /dev/null
- name: Run microbench
run: |
echo $AM_HOME
echo $NEMU_HOME
echo $NOOP_HOME
make -C $AM_HOME/apps/microbench ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME mainargs=test run 2> /dev/null
riscv-tests:
runs-on: self-hosted
name: Run riscv-tests
needs: [build-emu]
steps:
- name: Set env
run: |
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
echo ::set-env name=RVTEST_HOME::/home/ci-runner/xsenv/riscv-tests
- name: Run riscv-test
run: |
echo $NEMU_HOME
echo $NOOP_HOME
echo $RVTEST_HOME
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um SUITES+=rv64ua NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run 2> /dev/null
make -C $AM_HOME/apps/microbench ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME mainargs=test run 2> /dev/null
\ No newline at end of file
Subproject commit 5ca43398ac8b1b293291bd4e6e8c233be6c66968
Subproject commit 37d27a8f3b7d288c4663eebd8571018357fd827a
......@@ -5,7 +5,7 @@ import firrtl.AnnotationSeq
import firrtl.annotations.NoTargetAnnotation
import firrtl.options.{HasShellOptions, Shell, ShellOption}
import firrtl.stage.{FirrtlCli, RunFirrtlTransformAnnotation}
// import xstransforms.ShowPrintTransform
import xstransforms.ShowPrintTransform
import xstransforms.PrintModuleName
case class DisablePrintfAnnotation(m: String) extends NoTargetAnnotation
......@@ -78,7 +78,7 @@ object XiangShanStage {
(new XiangShanStage).execute(
args,
annotations ++ Seq(
// RunFirrtlTransformAnnotation(new ShowPrintTransform),
RunFirrtlTransformAnnotation(new ShowPrintTransform),
RunFirrtlTransformAnnotation(new PrintModuleName)
)
)
......
......@@ -5,7 +5,7 @@ import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.MDUOpType
import xiangshan.backend.fu.{ArrayMultiplier, Divider, FunctionUnit}
import xiangshan.backend.fu.{AbstractDivider, ArrayMultiplier, FunctionUnit, Radix2Divider}
class MulDivExeUnit(hasDiv: Boolean = true) extends Exu(
exuName = if(hasDiv) "MulDivExeUnit" else "MulExeUnit",
......@@ -31,7 +31,7 @@ class MulDivExeUnit(hasDiv: Boolean = true) extends Exu(
}.get
val div = supportedFunctionUnits.collectFirst {
case d: Divider => d
case d: AbstractDivider => d
}.orNull
// override inputs
......
......@@ -129,8 +129,9 @@ trait HasPipelineReg { this: FunctionUnit =>
object FunctionUnit extends HasXSParameter {
def multiplier = new ArrayMultiplier(XLEN+1)
def divider = new Divider(XLEN)
def divider = new SRT4Divider(XLEN)
def multiplier = new ArrayMultiplier(XLEN+1, Seq(0, 2))
def alu = new Alu
def jmp = new Jump
......
......@@ -4,8 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
import xiangshan.backend.fu.fpu.util.{C22, C32, C53}
class MulDivCtrl extends Bundle{
val sign = Bool()
......@@ -13,14 +12,17 @@ class MulDivCtrl extends Bundle{
val isHi = Bool() // return hi bits of result ?
}
class ArrayMultiplier(len: Int, latency: Int = 3)
extends FunctionUnit(
FuConfig(FuType.mul, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false, CertainLatency(latency)),
len
)
class AbstractMultiplier(len: Int, latency: Int = 2) extends FunctionUnit(
FuConfig(FuType.mul, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false, CertainLatency(latency)),
len
){
val ctrl = IO(Input(new MulDivCtrl))
}
class NaiveMultiplier(len: Int, latency: Int = 3)
extends AbstractMultiplier(len, latency)
with HasPipelineReg
{
val ctrl = IO(Input(new MulDivCtrl))
val (src1, src2) = (io.in.bits.src(0), io.in.bits.src(1))
......@@ -38,5 +40,134 @@ class ArrayMultiplier(len: Int, latency: Int = 3)
val res = Mux(ctrlVec.last.isHi, dataVec.last(2*xlen-1, xlen), dataVec.last(xlen-1,0))
io.out.bits.data := Mux(ctrlVec.last.isW, SignExt(res(31,0),xlen), res)
XSDebug(p"validVec:${Binary(Cat(validVec))} flushVec:${Binary(Cat(flushVec))}\n")
}
class ArrayMultiplier(len: Int, doReg: Seq[Int]) extends AbstractMultiplier(len, doReg.size) with HasPipelineReg {
val doRegSorted = doReg.sortWith(_ < _)
println(doRegSorted)
val (a, b) = (io.in.bits.src(0), io.in.bits.src(1))
val b_sext, bx2, neg_b, neg_bx2 = Wire(UInt((len+1).W))
b_sext := SignExt(b, len+1)
bx2 := b_sext << 1
neg_b := (~b_sext).asUInt()
neg_bx2 := neg_b << 1
val columns: Array[Seq[Bool]] = Array.fill(2*len)(Seq())
var last_x = WireInit(0.U(3.W))
for(i <- Range(0, len, 2)){
val x = if(i==0) Cat(a(1,0), 0.U(1.W)) else if(i+1==len) SignExt(a(i, i-1), 3) else a(i+1, i-1)
val pp_temp = MuxLookup(x, 0.U, Seq(
1.U -> b_sext,
2.U -> b_sext,
3.U -> bx2,
4.U -> neg_bx2,
5.U -> neg_b,
6.U -> neg_b
))
val s = pp_temp(len)
val t = MuxLookup(last_x, 0.U(2.W), Seq(
4.U -> 2.U(2.W),
5.U -> 1.U(2.W),
6.U -> 1.U(2.W)
))
last_x = x
val (pp, weight) = i match {
case 0 =>
(Cat(~s, s, s, pp_temp), 0)
case n if (n==len-1) || (n==len-2) =>
(Cat(~s, pp_temp, t), i-2)
case _ =>
(Cat(1.U(1.W), ~s, pp_temp, t), i-2)
}
for(j <- columns.indices){
if(j >= weight && j < (weight + pp.getWidth)){
columns(j) = columns(j) :+ pp(j-weight)
}
}
}
def addOneColumn(col: Seq[Bool], cin: Seq[Bool]): (Seq[Bool], Seq[Bool], Seq[Bool]) = {
var sum = Seq[Bool]()
var cout1 = Seq[Bool]()
var cout2 = Seq[Bool]()
col.size match {
case 1 => // do nothing
sum = col ++ cin
case 2 =>
val c22 = Module(new C22)
c22.io.in := col
sum = c22.io.out(0).asBool() +: cin
cout2 = Seq(c22.io.out(1).asBool())
case 3 =>
val c32 = Module(new C32)
c32.io.in := col
sum = c32.io.out(0).asBool() +: cin
cout2 = Seq(c32.io.out(1).asBool())
case 4 =>
val c53 = Module(new C53)
for((x, y) <- c53.io.in.take(4) zip col){
x := y
}
c53.io.in.last := (if(cin.nonEmpty) cin.head else 0.U)
sum = Seq(c53.io.out(0).asBool()) ++ (if(cin.nonEmpty) cin.drop(1) else Nil)
cout1 = Seq(c53.io.out(1).asBool())
cout2 = Seq(c53.io.out(2).asBool())
case n =>
val cin_1 = if(cin.nonEmpty) Seq(cin.head) else Nil
val cin_2 = if(cin.nonEmpty) cin.drop(1) else Nil
val (s_1, c_1_1, c_1_2) = addOneColumn(col take 4, cin_1)
val (s_2, c_2_1, c_2_2) = addOneColumn(col drop 4, cin_2)
sum = s_1 ++ s_2
cout1 = c_1_1 ++ c_2_1
cout2 = c_1_2 ++ c_2_2
}
(sum, cout1, cout2)
}
def max(in: Iterable[Int]): Int = in.reduce((a, b) => if(a>b) a else b)
def addAll(cols: Array[Seq[Bool]], depth: Int): (UInt, UInt) = {
if(max(cols.map(_.size)) <= 2){
val sum = Cat(cols.map(_(0)).reverse)
var k = 0
while(cols(k).size == 1) k = k+1
val carry = Cat(cols.drop(k).map(_(1)).reverse)
(sum, Cat(carry, 0.U(k.W)))
} else {
val columns_next = Array.fill(2*len)(Seq[Bool]())
var cout1, cout2 = Seq[Bool]()
for( i <- cols.indices){
val (s, c1, c2) = addOneColumn(cols(i), cout1)
columns_next(i) = s ++ cout2
cout1 = c1
cout2 = c2
}
val needReg = doRegSorted.contains(depth)
val toNextLayer = if(needReg)
columns_next.map(_.map(PipelineReg(doRegSorted.indexOf(depth) + 1)(_)))
else
columns_next
addAll(toNextLayer, depth+1)
}
}
val (sum, carry) = addAll(cols = columns, depth = 0)
val result = sum + carry
var ctrlVec = Seq(ctrl)
for(i <- 1 to latency){
ctrlVec = ctrlVec :+ PipelineReg(i)(ctrlVec(i-1))
}
val xlen = io.out.bits.data.getWidth
val res = Mux(ctrlVec.last.isHi, result(2*xlen-1, xlen), result(xlen-1,0))
io.out.bits.data := Mux(ctrlVec.last.isW, SignExt(res(31,0),xlen), res)
XSDebug(p"validVec:${Binary(Cat(validVec))} flushVec:${Binary(Cat(flushVec))}\n")
}
\ No newline at end of file
......@@ -5,13 +5,15 @@ import chisel3.util._
import xiangshan._
import utils._
class Divider(len: Int) extends FunctionUnit(
abstract class AbstractDivider(len: Int) extends FunctionUnit(
FuConfig(FuType.div, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false, UncertainLatency()),
len
) {
){
val ctrl = IO(Input(new MulDivCtrl))
val sign = ctrl.sign
}
class Radix2Divider(len: Int) extends AbstractDivider(len) {
def abs(a: UInt, sign: Bool): (Bool, UInt) = {
val s = a(len - 1) && sign
......@@ -72,7 +74,8 @@ class Divider(len: Int) extends FunctionUnit(
}
}
when(state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn)){
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn)
when(kill){
state := s_idle
}
......@@ -85,6 +88,6 @@ class Divider(len: Int) extends FunctionUnit(
io.out.bits.data := Mux(ctrlReg.isW, SignExt(res(31,0),xlen), res)
io.out.bits.uop := uopReg
io.out.valid := state === s_finish
io.out.valid := state === s_finish && !kill
io.in.ready := state === s_idle
}
\ No newline at end of file
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import utils.SignExt
import xiangshan.backend.fu.fpu.util.CSA3_2
/** A Radix-4 SRT Integer Divider
*
* 2 ~ (5 + (len+3)/2) cycles are needed for each division.
*/
class SRT4Divider(len: Int) extends AbstractDivider(len) {
val s_idle :: s_lzd :: s_normlize :: s_recurrence :: s_recovery :: s_finish :: Nil = Enum(6)
val state = RegInit(s_idle)
val newReq = (state === s_idle) && io.in.fire()
val cnt_next = Wire(UInt(log2Up((len+3)/2).W))
val cnt = RegEnable(cnt_next, state===s_normlize || state===s_recurrence)
val rec_enough = cnt_next === 0.U
def abs(a: UInt, sign: Bool): (Bool, UInt) = {
val s = a(len - 1) && sign
(s, Mux(s, -a, a))
}
val (a, b) = (io.in.bits.src(0), io.in.bits.src(1))
val uop = io.in.bits.uop
val (aSign, aVal) = abs(a, sign)
val (bSign, bVal) = abs(b, sign)
val aSignReg = RegEnable(aSign, newReq)
val qSignReg = RegEnable(aSign ^ bSign, newReq)
val uopReg = RegEnable(uop, newReq)
val ctrlReg = RegEnable(ctrl, newReq)
val divZero = b === 0.U
val divZeroReg = RegEnable(divZero, newReq)
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn)
switch(state){
is(s_idle){
when(io.in.fire()){ state := Mux(divZero, s_finish, s_lzd) }
}
is(s_lzd){ // leading zero detection
state := s_normlize
}
is(s_normlize){ // shift a/b
state := s_recurrence
}
is(s_recurrence){ // (ws[j+1], wc[j+1]) = 4(ws[j],wc[j]) - q(j+1)*d
when(rec_enough){ state := s_recovery }
}
is(s_recovery){ // if rem < 0, rem = rem + d
state := s_finish
}
is(s_finish){
when(io.out.fire()){ state := s_idle }
}
}
when(kill){
state := s_idle
}
/** Calculate abs(a)/abs(b) by recurrence
*
* ws, wc: partial remainder in carry-save form,
* in recurrence steps, ws/wc = 4ws[j]/4wc[j];
* in recovery step, ws/wc = ws[j]/wc[j];
* in final step, ws = abs(a)/abs(b).
*
* d: normlized divisor(1/2<=d<1)
*
* wLen = 3 integer bits + (len+1) frac bits
*/
def wLen = 3 + len + 1
val ws, wc = Reg(UInt(wLen.W))
val ws_next, wc_next = Wire(UInt(wLen.W))
val d = Reg(UInt(wLen.W))
val aLeadingZeros = RegEnable(
next = PriorityEncoder(ws(len-1, 0).asBools().reverse),
enable = state===s_lzd
)
val bLeadingZeros = RegEnable(
next = PriorityEncoder(d(len-1, 0).asBools().reverse),
enable = state===s_lzd
)
val diff = Cat(0.U(1.W), bLeadingZeros).asSInt() - Cat(0.U(1.W), aLeadingZeros).asSInt()
val isNegDiff = diff(diff.getWidth - 1)
val quotientBits = Mux(isNegDiff, 0.U, diff.asUInt())
val qBitsIsOdd = quotientBits(0)
val recoveryShift = RegEnable(len.U - bLeadingZeros, state===s_normlize)
val a_shifted, b_shifted = Wire(UInt(len.W))
a_shifted := Mux(isNegDiff,
ws(len-1, 0) << bLeadingZeros,
ws(len-1, 0) << aLeadingZeros
)
b_shifted := d(len-1, 0) << bLeadingZeros
val rem_temp = ws + wc
val rem_fixed = Mux(rem_temp(wLen-1), rem_temp + d, rem_temp)
val rem_abs = (rem_fixed << recoveryShift)(2*len, len+1)
when(newReq){
ws := Cat(0.U(4.W), Mux(divZero, a, aVal))
wc := 0.U
d := Cat(0.U(4.W), bVal)
}.elsewhen(state === s_normlize){
d := Cat(0.U(3.W), b_shifted, 0.U(1.W))
ws := Mux(qBitsIsOdd, a_shifted, a_shifted << 1)
}.elsewhen(state === s_recurrence){
ws := Mux(rec_enough, ws_next, ws_next << 2)
wc := Mux(rec_enough, wc_next, wc_next << 2)
}.elsewhen(state === s_recovery){
ws := rem_abs
}
cnt_next := Mux(state === s_normlize, (quotientBits + 3.U) >> 1, cnt - 1.U)
/** Quotient selection
*
* the quotient selection table use truncated 7-bit remainder
* and 3-bit divisor
*/
val sel_0 :: sel_d :: sel_dx2 :: sel_neg_d :: sel_neg_dx2 :: Nil = Enum(5)
val dx2, neg_d, neg_dx2 = Wire(UInt(wLen.W))
dx2 := d << 1
neg_d := (~d).asUInt() // add '1' in carry-save adder later
neg_dx2 := neg_d << 1
val q_sel = Wire(UInt(3.W))
val wc_adj = MuxLookup(q_sel, 0.U(2.W), Seq(
sel_d -> 1.U(2.W),
sel_dx2 -> 2.U(2.W)
))
val w_truncated = (ws(wLen-1, wLen-1-6) + wc(wLen-1, wLen-1-6)).asSInt()
val d_truncated = d(len-1, len-3)
val qSelTable = Array(
Array(12, 4, -4, -13),
Array(14, 4, -6, -15),
Array(15, 4, -6, -16),
Array(16, 4, -6, -18),
Array(18, 6, -8, -20),
Array(20, 6, -8, -20),
Array(20, 8, -8, -22),
Array(24, 8, -8, -24)
)
// ge(x): w_truncated >= x
var ge = Map[Int, Bool]()
for(row <- qSelTable){
for(k <- row){
if(!ge.contains(k)) ge = ge + (k -> (w_truncated >= k.S(7.W)))
}
}
q_sel := MuxLookup(d_truncated, sel_0,
qSelTable.map(x =>
MuxCase(sel_neg_dx2, Seq(
ge(x(0)) -> sel_dx2,
ge(x(1)) -> sel_d,
ge(x(2)) -> sel_0,
ge(x(3)) -> sel_neg_d
))
).zipWithIndex.map({case(v, i) => i.U -> v})
)
/** Calculate (ws[j+1],wc[j+1]) by a [3-2]carry-save adder
*
* (ws[j+1], wc[j+1]) = 4(ws[j],wc[j]) - q(j+1)*d
*/
val csa = Module(new CSA3_2(wLen))
csa.io.in(0) := ws
csa.io.in(1) := Cat(wc(wLen-1, 2), wc_adj)
csa.io.in(2) := MuxLookup(q_sel, 0.U, Seq(
sel_d -> neg_d,
sel_dx2 -> neg_dx2,
sel_neg_d -> d,
sel_neg_dx2 -> dx2
))
ws_next := csa.io.out(0)
wc_next := csa.io.out(1) << 1
// On the fly quotient conversion
val q, qm = Reg(UInt(len.W))
when(newReq){
q := 0.U
qm := 0.U
}.elsewhen(state === s_recurrence){
val qMap = Seq(
sel_0 -> (q, 0),
sel_d -> (q, 1),
sel_dx2 -> (q, 2),
sel_neg_d -> (qm, 3),
sel_neg_dx2 -> (qm, 2)
)
q := MuxLookup(q_sel, 0.U,
qMap.map(m => m._1 -> Cat(m._2._1(len-3, 0), m._2._2.U(2.W)))
)
val qmMap = Seq(
sel_0 -> (qm, 3),
sel_d -> (q, 0),
sel_dx2 -> (q, 1),
sel_neg_d -> (qm, 2),
sel_neg_dx2 -> (qm, 1)
)
qm := MuxLookup(q_sel, 0.U,
qmMap.map(m => m._1 -> Cat(m._2._1(len-3, 0), m._2._2.U(2.W)))
)
}.elsewhen(state === s_recovery){
q := Mux(rem_temp(wLen-1), qm, q)
}
val remainder = Mux(aSignReg, -ws(len-1, 0), ws(len-1, 0))
val quotient = Mux(qSignReg, -q, q)
val res = Mux(ctrlReg.isHi,
Mux(divZeroReg, ws(len-1, 0), remainder),
Mux(divZeroReg, Fill(len, 1.U(1.W)), quotient)
)
io.in.ready := state===s_idle
io.out.valid := state===s_finish && !kill
io.out.bits.data := Mux(ctrlReg.isW,
SignExt(res(31, 0), len),
res
)
io.out.bits.uop := uopReg
}
......@@ -21,7 +21,7 @@ class DivSqrt extends FPUSubModule(
val uopReg = RegEnable(io.in.bits.uop, io.in.fire())
val kill = uopReg.roqIdx.needFlush(io.redirectIn)
val kill = state=/=s_idle && uopReg.roqIdx.needFlush(io.redirectIn)
val rmReg = RegEnable(rm, io.in.fire())
val isDiv = !op(0)
val isDivReg = RegEnable(isDiv, io.in.fire())
......
......@@ -295,7 +295,7 @@ class ReservationStationNew
val srcStateSeq = Seq(enqUop.src1State, enqUop.src2State, enqUop.src3State)
val srcDataSeq = Seq(io.enqData.src1, io.enqData.src2, io.enqData.src3)
val enqPtr = Mux(tailPtr.head(1).asBool, selectedIdxReg, tailPtr.tail(1))
val enqPtr = Mux(tailPtr.head(1).asBool, deqIdx, tailPtr.tail(1))
val enqIdx_data = idxQueue(enqPtr)
val enqIdx_ctrl = tailAfterRealDeq.tail(1)
val enqIdxNext = RegNext(enqIdx_data)
......
......@@ -281,7 +281,7 @@ class Roq extends XSModule with HasCircularQueuePtrHelper {
val retireCounter = Mux(state === s_idle, commitCnt, 0.U)
XSInfo(retireCounter > 0.U, "retired %d insts\n", retireCounter)
val commitOffset = PriorityEncoder((validCommit :+ false.B).map(!_))
io.commitRoqIndex.valid := io.commits(0).valid && !io.commits(0).bits.isWalk
io.commitRoqIndex.valid := state === s_idle
io.commitRoqIndex.bits := deqPtrExt + commitOffset
// commit branch to brq
......
......@@ -54,7 +54,7 @@ class StoreMissEntry extends DCacheModule
when (state =/= s_invalid) {
XSDebug("entry: %d state: %d\n", io.id, state)
XSDebug("entry: %d state: %d idx: %x tag: %x\n", io.id, state, io.idx.bits, io.tag.bits)
}
// --------------------------------------------
......@@ -158,12 +158,13 @@ class StoreMissQueue extends DCacheModule
val replay_arb = Module(new Arbiter(new DCacheLineReq, cfg.nStoreMissEntries))
val resp_arb = Module(new Arbiter(new DCacheLineResp, cfg.nStoreMissEntries))
val idx_matches = Wire(Vec(cfg.nLoadMissEntries, Bool()))
val tag_matches = Wire(Vec(cfg.nLoadMissEntries, Bool()))
val idx_matches = Wire(Vec(cfg.nStoreMissEntries, Bool()))
val tag_matches = Wire(Vec(cfg.nStoreMissEntries, Bool()))
val tag_match = Mux1H(idx_matches, tag_matches)
val idx_match = idx_matches.reduce(_||_)
XSDebug("idx_match: %b tag_match: %b\n", idx_match, tag_match)
val req = io.lsu.req
val entry_alloc_idx = Wire(UInt())
......
......@@ -204,7 +204,7 @@ int difftest_step(DiffState *s) {
ds.exceptionNo = s->cause;
ds.mtval = s->reg_scala[DIFFTEST_MTVAL];
ds.stval = s->reg_scala[DIFFTEST_STVAL];
ref_disambiguate_exec(&s->cause);
ref_disambiguate_exec(&ds);
}else{
ref_difftest_exec(1);
}
......
......@@ -201,21 +201,24 @@ class L1plusCacheTest extends FlatSpec with ChiselScalatestTester with Matchers
}
// emulated queue
class IdPool(val nReqIds: Int) {
class IdPool(val nReqIds: Int, name: String) {
val freeIds = new Array[Boolean](nReqIds)
def allocate(): Int = {
for (i <- 0 until freeIds.size) {
if (freeIds(i)) {
println(f"$name allocate: $i")
freeIds(i) = false
return i
}
}
// no free id to allocate
println(f"$name allocate failed")
return -1
}
def free(id: Int): Unit = {
println(f"$name free: $id")
assert(!freeIds(id))
freeIds(id) = true
}
......@@ -248,7 +251,7 @@ case class QueueEntry(
class Queue(nEntries: Int, name: String) {
// Queue
// ---------------------------------------
val idPool = new IdPool(nEntries)
val idPool = new IdPool(nEntries, name + "IdPool")
val queue = new ArrayBuffer[QueueEntry]()
def enq(req: Req) = {
// for unissued reqs, they have id = -1
......@@ -313,48 +316,51 @@ class StoreQueue(nEntries: Int) extends Queue(nEntries, "StoreQueue") {
def sendReq(port: DCacheLineIO): Unit = {
val req = port.req
// has last cycle's req been fired?
if (reqWaiting && req.ready.peek().litToBoolean) {
reqWaiting = false
// no requests waiting on line
// reset valid signal
req.valid.poke(false.B)
}
// can we send a new request in this cycle
val reqIdx = select()
if (reqWaiting || reqIdx == -1) {
return
}
if (!reqWaiting) {
val reqIdx = select()
if (reqIdx == -1) {
// no more request to send
req.valid.poke(false.B)
return
}
val tId = idPool.allocate()
if (tId == -1) {
return
val tId = idPool.allocate()
if (tId == -1) {
// no more request to send
req.valid.poke(false.B)
return
}
// try sending a new request in this cycle
// select a req to issue
reqWaiting = true
issue(reqIdx, tId)
val CMD_WRITE = MemoryOpConstants.M_XWR
val FULL_MASK = BigInt("ffffffffffffffff", 16).U
val r = queue(reqIdx).req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_WRITE)
req.bits.addr.poke(r.addr.U)
req.bits.data.poke(r.data.U)
req.bits.mask.poke(FULL_MASK)
req.bits.meta.id.poke(tId.U)
req.bits.meta.vaddr.poke(r.addr.U)
req.bits.meta.paddr.poke(r.addr.U)
// req.bits.meta.uop.poke(0.U.asTypeOf(new MicroOp))
req.bits.meta.mmio.poke(false.B)
req.bits.meta.tlb_miss.poke(false.B)
req.bits.meta.mask.poke(FULL_MASK)
req.bits.meta.replay.poke(false.B)
}
// try sending a new request in this cycle
// select a req to issue
reqWaiting = true
issue(reqIdx, tId)
val CMD_WRITE = MemoryOpConstants.M_XWR
val FULL_MASK = BigInt("ffffffffffffffff", 16).U
val r = queue(reqIdx).req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_WRITE)
req.bits.addr.poke(r.addr.U)
req.bits.data.poke(r.data.U)
req.bits.mask.poke(FULL_MASK)
req.bits.meta.id.poke(tId.U)
req.bits.meta.vaddr.poke(r.addr.U)
req.bits.meta.paddr.poke(r.addr.U)
// req.bits.meta.uop.poke(0.U.asTypeOf(new MicroOp))
req.bits.meta.mmio.poke(false.B)
req.bits.meta.tlb_miss.poke(false.B)
req.bits.meta.mask.poke(FULL_MASK)
req.bits.meta.replay.poke(false.B)
if (req.valid.peek().litToBoolean && req.ready.peek().litToBoolean) {
reqWaiting = false
}
}
def handleResp(port: DCacheLineIO) = {
......@@ -380,37 +386,40 @@ class LoadQueue(nEntries: Int) extends Queue(nEntries, "LoadQueue") {
def sendReq(port: L1plusCacheIO): Unit = {
val req = port.req
// has last cycle's req been fired?
if (reqWaiting && req.ready.peek().litToBoolean) {
reqWaiting = false
// no requests waiting on line
// reset valid signal
req.valid.poke(false.B)
}
// can we send a new request in this cycle
val reqIdx = select()
if (reqWaiting || reqIdx == -1) {
return
}
if (!reqWaiting) {
val reqIdx = select()
if (reqIdx == -1) {
// no more request to send
req.valid.poke(false.B)
return
}
val tId = idPool.allocate()
if (tId == -1) {
return
}
val tId = idPool.allocate()
if (tId == -1) {
// no more request to send
req.valid.poke(false.B)
return
}
// try sending a new request in this cycle
// select a req to issue
// try sending a new request in this cycle
// select a req to issue
reqWaiting = true
issue(reqIdx, tId)
reqWaiting = true
issue(reqIdx, tId)
val CMD_READ = MemoryOpConstants.M_XRD
val CMD_READ = MemoryOpConstants.M_XRD
val r = queue(reqIdx).req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_READ)
req.bits.addr.poke(r.addr.U)
req.bits.id.poke(tId.U)
}
val r = queue(reqIdx).req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_READ)
req.bits.addr.poke(r.addr.U)
req.bits.id.poke(tId.U)
if (req.valid.peek().litToBoolean && req.ready.peek().litToBoolean) {
reqWaiting = false
}
}
def handleResp(port: L1plusCacheIO) = {
......
package cache
import scala.collection.mutable.ArrayBuffer
import chipsalliance.rocketchip.config.{Field, Parameters}
import chisel3._
import chisel3.util._
import chiseltest.experimental.TestOptionBuilder._
import chiseltest.internal.VerilatorBackendAnnotation
import chiseltest._
import chisel3.experimental.BundleLiterals._
import firrtl.stage.RunFirrtlTransformAnnotation
import chiseltest.ChiselScalatestTester
import device.AXI4RAM
import freechips.rocketchip.amba.axi4.AXI4UserYanker
import freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp}
import freechips.rocketchip.tilelink.{TLBuffer, TLCacheCork, TLToAXI4, TLXbar}
import org.scalatest.{FlatSpec, Matchers}
import sifive.blocks.inclusivecache.{CacheParameters, InclusiveCache, InclusiveCacheMicroParameters, InclusiveCacheControlParameters}
import utils.{DebugIdentityNode, HoldUnless, XSDebug}
import xiangshan.{HasXSLog, MicroOp}
import xiangshan.cache.{DCache, L1plusCache, Uncache, DCacheWordIO, DCacheLineIO, L1plusCacheIO, MemoryOpConstants}
import xiangshan.testutils.AddSinks
import xstransforms.PrintModuleName
import scala.util.Random
class L2NonInclusiveGetTestTopIO extends Bundle {
val l1plus = new L1plusCacheIO()
val dcacheStore = new DCacheLineIO()
val l2Flush = new DCacheWordIO
}
class L2NonInclusiveGetTestTop()(implicit p: Parameters) extends LazyModule {
val uncache = LazyModule(new Uncache())
val dcache = LazyModule(new DCache())
val l1plusCache = LazyModule(new L1plusCache())
val l2 = LazyModule(new InclusiveCache(
CacheParameters(
level = 2,
ways = 4,
sets = 4 * 1024 / (64 * 4 * 4),
blockBytes = 64,
beatBytes = 32,
cacheName = s"L2"
),
InclusiveCacheMicroParameters(
writeBytes = 8
),
Some(InclusiveCacheControlParameters(
address = 0x8000000L,
beatBytes = 8))))
val ram = LazyModule(new AXI4RAM(
AddressSet(0x0L, 0x7ffffffL),
memByte = 128 * 1024 * 1024,
useBlackBox = false
))
val xbar = TLXbar()
xbar := TLBuffer() := DebugIdentityNode() := dcache.clientNode
xbar := TLBuffer() := DebugIdentityNode() := l1plusCache.clientNode
l2.node := DebugIdentityNode() := xbar
ram.node :=
AXI4UserYanker() :=
TLToAXI4() :=
TLBuffer() :=
TLCacheCork() :=
DebugIdentityNode() :=
l2.node
// connect uncache access to l2 control node
l2.ctlnode.get := DebugIdentityNode() := uncache.clientNode
lazy val module = new LazyModuleImp(this) with HasXSLog {
val io = IO(Flipped(new L2NonInclusiveGetTestTopIO))
AddSinks()
dcache.module.io <> DontCare
dcache.module.io.lsu.store <> io.dcacheStore
l1plusCache.module.io <> io.l1plus
uncache.module.io.lsroq <> io.l2Flush
}
}
class L2NonInclusiveGetTest extends FlatSpec with ChiselScalatestTester with Matchers {
behavior of "L2Cache"
val mem_size = 128 * 1024 * 1024
val block_size = 64
val block_bits = log2Up(block_size)
// val nblocks = mem_size / block_size
val nblocks = 100
// data structures
// our golden version cache
val cache_blocks = new Array[BigInt](nblocks)
for (i <- 0 until nblocks) {
cache_blocks(i) = BigInt(0)
}
// ----------------------------------------
// useful request parameter values
val CMD_READ = MemoryOpConstants.M_XRD
val CMD_WRITE = MemoryOpConstants.M_XWR
// 64bit full mask
val FULL_MASK_64 = BigInt("ffffffffffffffff", 16).U
val L2_FLUSH_BASE_ADDR = 0x8000000L
val CONFIG_ADDR = L2_FLUSH_BASE_ADDR + 0x0
val FLUSH64_ADDR = L2_FLUSH_BASE_ADDR + 0x200
val FLUSH32_ADDR = L2_FLUSH_BASE_ADDR + 0x240
val r = scala.util.Random
top.Parameters.set(top.Parameters.debugParameters)
val annos = Seq(
VerilatorBackendAnnotation,
RunFirrtlTransformAnnotation(new PrintModuleName)
)
it should "run" in {
implicit val p = Parameters((site, up, here) => {
case L1plusCacheTestKey => 0
})
test(LazyModule(new L2NonInclusiveGetTestTop()).module)
.withAnnotations(annos){ c =>
c.clock.step(100)
val sq = new StoreQueue(8)
val lq = new LoadQueue(8)
def init() = {
sq.init()
lq.init()
// initialize DUT inputs
c.io.dcacheStore.req.valid.poke(false.B)
c.io.dcacheStore.resp.ready.poke(false.B)
c.io.l1plus.req.valid.poke(false.B)
c.io.l1plus.resp.ready.poke(false.B)
c.io.l1plus.flush.poke(false.B)
c.io.l2Flush.req.valid.poke(false.B)
c.io.l2Flush.resp.ready.poke(false.B)
}
def mmio_read(addr: BigInt): BigInt = {
// send req
val req = c.io.l2Flush.req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_READ)
req.bits.addr.poke(addr.U)
req.bits.data.poke(0.U)
req.bits.mask.poke(FULL_MASK_64)
req.bits.meta.id.poke(0.U)
req.bits.meta.vaddr.poke(addr.U)
req.bits.meta.paddr.poke(addr.U)
// req.bits.meta.uop.poke(0.U.asTypeOf(new MicroOp))
req.bits.meta.mmio.poke(true.B)
req.bits.meta.tlb_miss.poke(false.B)
req.bits.meta.mask.poke(FULL_MASK_64)
req.bits.meta.replay.poke(false.B)
while (!req.ready.peek().litToBoolean) {
c.clock.step()
}
// actually send the req
c.clock.step()
// lower valid
req.valid.poke(false.B)
// recv resp
val resp = c.io.l2Flush.resp
resp.ready.poke(true.B)
while (!resp.valid.peek().litToBoolean) {
c.clock.step()
}
val data = resp.bits.data.peek().litValue
// actually recv the response
c.clock.step()
// lower ready
resp.ready.poke(false.B)
return data
}
def mmio_write(addr: BigInt, data: BigInt) = {
// send req
val req = c.io.l2Flush.req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_WRITE)
req.bits.addr.poke(addr.U)
req.bits.data.poke(data.U)
req.bits.mask.poke(FULL_MASK_64)
req.bits.meta.id.poke(0.U)
req.bits.meta.vaddr.poke(addr.U)
req.bits.meta.paddr.poke(addr.U)
// req.bits.meta.uop.poke(0.U.asTypeOf(new MicroOp))
req.bits.meta.mmio.poke(true.B)
req.bits.meta.tlb_miss.poke(false.B)
req.bits.meta.mask.poke(FULL_MASK_64)
req.bits.meta.replay.poke(false.B)
while (!req.ready.peek().litToBoolean) {
c.clock.step()
}
// actually send the req
c.clock.step()
// lower valid
req.valid.poke(false.B) // recv resp
val resp = c.io.l2Flush.resp
resp.ready.poke(true.B)
while (!resp.valid.peek().litToBoolean) {
c.clock.step()
}
// actually recv the response
c.clock.step()
// lower ready
resp.ready.poke(false.B)
}
def get_l2_configurations() = {
val config = mmio_read(CONFIG_ADDR)
val nBank = config & 0xf
val nWay = config >> 8 & 0xf
val nSet = 1 << (config.toInt >> 16 & 0xf)
val nBlock = 1 << (config.toInt >> 24 & 0xf)
println(f"L2 configuration: nBank: $nBank nWay: $nWay nSet: $nSet nBlock: $nBlock")
}
def flush_l2_block(addr: BigInt) = {
mmio_write(FLUSH64_ADDR, addr)
println(f"L2 flush block: $addr%x")
}
def flush_l1plus() = {
c.io.l1plus.flush.poke(true.B)
while (!c.io.l1plus.empty.peek().litToBoolean) {
c.clock.step()
}
c.io.l1plus.flush.poke(false.B)
}
def flush_l2_range(begin: BigInt, end: BigInt) = {
var addr = begin >> block_bits << block_bits
while (addr < end) {
flush_l2_block(addr)
addr += block_size
}
}
def evaluate() = {
while (!sq.isFinished() || !lq.isFinished()) {
sq.tick(c.io.dcacheStore)
lq.tick(c.io.l1plus)
c.clock.step()
}
}
get_l2_configurations()
// ----------------------------------------
// scan test
def populate_memory() = {
println(s"scan test")
init()
// first, initialize every memory block with random numbers
for (i <- 0 until nblocks) {
val addr = i * 64
val words = (0 until 8) map { _ =>
(BigInt(r.nextLong() & 0x7fffffffffffffffL))
}
val data = words.foldLeft(BigInt(0))((sum, i) => sum << 64 | i)
cache_blocks(i) = data
println(f"enq store addr: $addr%x data: $data%x")
sq.enq(Req(addr, data))
}
// execute reqs
evaluate()
}
def flush_memory() = {
flush_l2_range(0, (nblocks - 1)* block_size)
}
def read_memory() = {
// read them out
for (i <- 0 until nblocks) {
val addr = i * 64
val data = cache_blocks(i)
println(f"enq load addr: $addr%x data: $data%x")
lq.enq(Req(addr, data))
}
// execute reqs
evaluate()
}
for (i <- 0 until 10) {
populate_memory()
flush_memory()
// these loads should cause get miss
flush_l1plus()
read_memory()
populate_memory()
// these loads should not miss
flush_l1plus()
read_memory()
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册