From 560404992747a8752aa992c5e98e89ecb3f0056a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 9 Sep 2016 11:08:39 -0700 Subject: [PATCH 01/24] tilelink2 Buffer: support an unlimited number of channels --- src/main/scala/uncore/tilelink2/Buffer.scala | 34 +++++++++----------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala index 84d6c21b..adfe4c4b 100644 --- a/src/main/scala/uncore/tilelink2/Buffer.scala +++ b/src/main/scala/uncore/tilelink2/Buffer.scala @@ -14,25 +14,23 @@ class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule val in = node.bundleIn val out = node.bundleOut } - - val in = io.in(0) - val out = io.out(0) - - out.a <> Queue(in .a, entries, pipe) - in .d <> Queue(out.d, entries, pipe) - val edge = node.edgesOut(0) // same as edgeIn(0) - if (edge.manager.anySupportAcquire && edge.client.anySupportProbe) { - in .b <> Queue(out.b, entries, pipe) - out.c <> Queue(in .c, entries, pipe) - out.e <> Queue(out.e, entries, pipe) - } else { - in.b.valid := Bool(false) - in.c.ready := Bool(true) - in.e.ready := Bool(true) - out.b.ready := Bool(true) - out.c.valid := Bool(false) - out.e.valid := Bool(false) + ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) => + out.a <> Queue(in .a, entries, pipe) + in .d <> Queue(out.d, entries, pipe) + + if (edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe) { + in .b <> Queue(out.b, entries, pipe) + out.c <> Queue(in .c, entries, pipe) + out.e <> Queue(out.e, entries, pipe) + } else { + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) + } } } } From d6261e8ce8c047aa49dc061a37c80e100ebf54c1 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 9 Sep 2016 20:55:56 -0700 Subject: [PATCH 02/24] tilelink2 Edge: add a numBeats1 method for predecremented code --- src/main/scala/uncore/tilelink2/Edges.scala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 558af74b..a9993e65 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -192,7 +192,17 @@ class TLEdge( val cutoff = log2Ceil(manager.beatBytes) val small = if (manager.maxTransfer <= manager.beatBytes) Bool(true) else size <= UInt(cutoff) val decode = UIntToOH(size, maxLgSize+1) >> cutoff - Mux(!hasData || small, UInt(1), decode) + Mux(hasData, decode | small.asUInt, UInt(1)) + } + } + } + + def numBeats1(x: TLChannel): UInt = { + x match { + case _: TLBundleE => UInt(0) + case bundle: TLDataChannel => { + val decode = UIntToOH1(size(bundle), maxLgSize) >> log2Ceil(manager.beatBytes) + Mux(hasData(bundle), decode, UInt(0)) } } } From 488b93d146fad4dc95db57bfe643a21bde204ac0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 9 Sep 2016 20:56:48 -0700 Subject: [PATCH 03/24] tilelink2 Parameters: if you support PutPartial, you must support PutFull --- src/main/scala/uncore/tilelink2/Parameters.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 355fdb3a..82e0500a 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -117,9 +117,7 @@ case class TLManagerParameters( address.combinations(2).foreach({ case Seq(x,y) => require (!x.overlaps(y)) }) - address.foreach({ case a => - require (supportsAcquire.none || a.alignment1 >= supportsAcquire.max-1) - }) + require (supportsPutFull.contains(supportsPutPartial)) // Largest support transfer of all types val maxTransfer = List( @@ -218,6 +216,8 @@ case class TLClientParameters( supportsPutPartial: TransferSizes = TransferSizes.none, supportsHint: Boolean = false) { + require (supportsPutFull.contains(supportsPutPartial)) + val maxTransfer = List( supportsProbe.max, supportsArithmetic.max, From 17f7ab18dec66ff5635fded41e9db1a7886d1297 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 9 Sep 2016 20:57:20 -0700 Subject: [PATCH 04/24] tilelink2 RAMModel: model the state a RAM would have for Put+Gets --- .../scala/uncore/tilelink2/RAMModel.scala | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 src/main/scala/uncore/tilelink2/RAMModel.scala diff --git a/src/main/scala/uncore/tilelink2/RAMModel.scala b/src/main/scala/uncore/tilelink2/RAMModel.scala new file mode 100644 index 00000000..b1131588 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/RAMModel.scala @@ -0,0 +1,194 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import chisel3.util.LFSR16 + +class TLRAMModel extends LazyModule +{ + val node = TLIdentityNode() + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + // Pass through all signals unchanged + io.out <> io.in + require (io.out.size == 1) // !!! support multiple clients + + val edge = node.edgesIn(0) + val endAddress = edge.manager.maxAddress + 1 + val endSourceId = edge.client.endSourceId + val maxTransfer = edge.manager.maxTransfer + val beatBytes = edge.manager.beatBytes + val endAddressHi = (endAddress / beatBytes).intValue + val maxLgBeats = log2Up(maxTransfer/beatBytes) + val shift = log2Ceil(beatBytes) + val decTrees = log2Ceil(maxTransfer/beatBytes) + val addressBits = log2Up(endAddress) + val countBits = log2Up(endSourceId) + val sizeBits = edge.bundle.sizeBits + + class ByteMonitor extends Bundle { + val valid = Bool() + val value = UInt(width = 8) + } + class FlightMonitor extends Bundle { + val base = UInt(width = addressBits) + val size = UInt(width = sizeBits) + val opcode = UInt(width = 3) + } + + // !!! Must somehow power-on with these all initialized with 0 + val shadow = Seq.fill(beatBytes) { Mem(endAddressHi, new ByteMonitor) } + val inc_bytes = Seq.fill(beatBytes) { Mem(endAddressHi, UInt(width = countBits)) } + val dec_bytes = Seq.fill(beatBytes) { Mem(endAddressHi, UInt(width = countBits)) } + val inc_trees = Seq.tabulate(decTrees) { i => Mem(endAddressHi >> (i+1), UInt(width = countBits)) } + val dec_trees = Seq.tabulate(decTrees) { i => Mem(endAddressHi >> (i+1), UInt(width = countBits)) } + + // Don't care on power-up + val flight = Reg(Vec(endSourceId, new FlightMonitor)) + + // Process A access requests + val a = RegNext(io.in(0).a) + val a_beats1 = edge.numBeats1(a.bits) + val a_size = edge.size(a.bits) + val a_sizeOH = UIntToOH(a_size) + val a_counter = RegInit(UInt(0, width = maxLgBeats)) + val a_counter1 = a_counter - UInt(1) + val a_first = a_counter === UInt(0) + val a_addr_hi = a.bits.addr_hi | (a_beats1 & ~a_counter1) + val a_base = edge.address(a.bits) + val a_mask = edge.mask(a_base, a_size) + + // What is the request? + val a_flight = Wire(new FlightMonitor) + a_flight.base := a_base + a_flight.size := a_size + a_flight.opcode := a.bits.opcode + + // Grab the concurrency state we need + val a_inc_bytes = inc_bytes.map(_.read(a_addr_hi)) + val a_dec_bytes = dec_bytes.map(_.read(a_addr_hi)) + val a_inc_trees = inc_trees.zipWithIndex.map{ case (m, i) => m.read(a_addr_hi >> (i+1)) } + val a_dec_trees = dec_trees.zipWithIndex.map{ case (m, i) => m.read(a_addr_hi >> (i+1)) } + val a_inc_tree = a_inc_trees.fold(UInt(0))(_ + _) + val a_dec_tree = a_dec_trees.fold(UInt(0))(_ + _) + val a_inc = a_inc_bytes.map(_ + a_inc_tree) + val a_dec = a_dec_bytes.map(_ + a_dec_tree) + + when (a.fire()) { + // Record the request so we can handle it's response + flight(a.bits.source) := a_flight + a_counter := Mux(a_first, a_beats1, a_counter1) + + // !!! atomics + assert (a.bits.opcode =/= TLMessages.Acquire) + + // Increase the per-byte flight counter for the whole transaction + when (a_first && a.bits.opcode =/= TLMessages.Hint) { + when (a_size <= UInt(shift)) { + for (i <- 0 until beatBytes) { + when (a_mask(i)) { // not a.bits.mask; the full mask + inc_bytes(i).write(a_addr_hi, a_inc_bytes(i) + UInt(1)) + } + } + } + for (i <- 0 until inc_trees.size) { + when (a_sizeOH(i+shift+1)) { + inc_trees(i).write(a_addr_hi >> (i+1), a_inc_trees(i) + UInt(1)) + } + } + } + + when (a.bits.opcode === TLMessages.PutFullData || a.bits.opcode === TLMessages.PutPartialData) { + for (i <- 0 until beatBytes) { + val set = Wire(new ByteMonitor) + val busy = a_inc(i) - a_dec(i) - (!a_first).asUInt + set.valid := busy === UInt(0) + set.value := a.bits.data(8*(i+1)-1, 8*i) + when (a.bits.mask(i)) { + shadow(i).write(a_addr_hi, set) + printf("P 0x%x := 0x%x #%d\n", a_addr_hi << shift | UInt(i), set.value, busy) + } + } + } + } + + // Process D access responses + val d = RegNext(io.out(0).d) + val d_bypass = a.valid && d.bits.source === a.bits.source + val d_flight = Mux(d_bypass, a_flight, flight(d.bits.source)) + val d_beats1 = edge.numBeats1(d.bits) + val d_size = edge.size(d.bits) + val d_sizeOH = UIntToOH(d_size) + val d_counter = RegInit(UInt(0, width = maxLgBeats)) + val d_counter1 = d_counter - UInt(1) + val d_first = d_counter === UInt(0) + val d_last = d_counter === UInt(1) || d_beats1 === UInt(0) + val d_base = d_flight.base + val d_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1) + val d_mask = edge.mask(d_base, d_size) + + // Grab the concurrency state we need + val d_inc_bytes = inc_bytes.map(_.read(d_addr_hi)) + val d_dec_bytes = dec_bytes.map(_.read(d_addr_hi)) + val d_inc_trees = inc_trees.zipWithIndex.map{ case (m, i) => m.read(d_addr_hi >> (i+1)) } + val d_dec_trees = dec_trees.zipWithIndex.map{ case (m, i) => m.read(d_addr_hi >> (i+1)) } + val d_inc_tree = d_inc_trees.fold(UInt(0))(_ + _) + val d_dec_tree = d_dec_trees.fold(UInt(0))(_ + _) + val d_inc = d_inc_bytes.map(_ + d_inc_tree) + val d_dec = d_dec_bytes.map(_ + d_dec_tree) + val d_shadow = shadow.map(_.read(d_addr_hi)) + + when (d.fire()) { + assert (d_size === d_flight.size) + d_counter := Mux(d_first, d_beats1, d_counter1) + + when (d_flight.opcode === TLMessages.Hint) { + assert (d.bits.opcode === TLMessages.HintAck) + } + + // Decreaes the per-byte flight counter for the whole transaction + when (d_last && d_flight.opcode =/= TLMessages.Hint) { + when (d_size <= UInt(shift)) { + for (i <- 0 until beatBytes) { + when (d_mask(i)) { + dec_bytes(i).write(d_addr_hi, d_dec_bytes(i) + UInt(1)) + } + } + } + for (i <- 0 until dec_trees.size) { + when (d_sizeOH(i+shift+1)) { + dec_trees(i).write(d_addr_hi >> (i+1), d_dec_trees(i) + UInt(1)) + } + } + } + + when (d_flight.opcode === TLMessages.PutFullData || d_flight.opcode === TLMessages.PutPartialData) { + assert (d.bits.opcode === TLMessages.AccessAck) + } + + // !!! atomics + + when (d_flight.opcode === TLMessages.Get) { + assert (d.bits.opcode === TLMessages.AccessAckData) + for (i <- 0 until beatBytes) { + val got = d.bits.data(8*(i+1)-1, 8*i) + val shadow = Wire(init = d_shadow(i)) + when (d_mask(i)) { + when (!shadow.valid) { + printf("G 0x%x := undefined due to concurrent accesses\n", d_addr_hi << shift | UInt(i)) + } .otherwise { + printf("G 0x%x := 0x%x\n", d_addr_hi << shift | UInt(i), shadow.value) + assert (shadow.value === got) + } + } + } + } + } + } +} From 98a4facac7308029756953c13e6ca86a27f714ab Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sat, 10 Sep 2016 00:24:57 -0700 Subject: [PATCH 05/24] tilelink2 RAMModel: clear Mems on power-up --- .../scala/uncore/tilelink2/RAMModel.scala | 159 ++++++++++++------ 1 file changed, 105 insertions(+), 54 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RAMModel.scala b/src/main/scala/uncore/tilelink2/RAMModel.scala index b1131588..e85bd5d4 100644 --- a/src/main/scala/uncore/tilelink2/RAMModel.scala +++ b/src/main/scala/uncore/tilelink2/RAMModel.scala @@ -15,10 +15,11 @@ class TLRAMModel extends LazyModule val out = node.bundleOut } - // Pass through all signals unchanged - io.out <> io.in require (io.out.size == 1) // !!! support multiple clients + val in = io.in(0) + val out = io.out(0) + val edge = node.edgesIn(0) val endAddress = edge.manager.maxAddress + 1 val endSourceId = edge.client.endSourceId @@ -32,6 +33,27 @@ class TLRAMModel extends LazyModule val countBits = log2Up(endSourceId) val sizeBits = edge.bundle.sizeBits + // Reset control logic + val wipeIndex = RegInit(UInt(0, width = log2Ceil(endAddressHi) + 1)) + val wipe = !wipeIndex(log2Ceil(endAddressHi)) + wipeIndex := wipeIndex + wipe.asUInt + + // Block traffic while wiping Mems + in.a.ready := out.a.ready && !wipe + out.a.valid := in.a.valid && !wipe + out.a.bits := in.a.bits + out.d.ready := in.d.ready && !wipe + in.d.valid := out.d.valid && !wipe + in.d.bits := out.d.bits + + // BCE unsupported + in.b.valid := Bool(false) + out.c.valid := Bool(false) + out.e.valid := Bool(false) + out.b.ready := Bool(true) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + class ByteMonitor extends Bundle { val valid = Bool() val value = UInt(width = 8) @@ -42,33 +64,39 @@ class TLRAMModel extends LazyModule val opcode = UInt(width = 3) } - // !!! Must somehow power-on with these all initialized with 0 val shadow = Seq.fill(beatBytes) { Mem(endAddressHi, new ByteMonitor) } val inc_bytes = Seq.fill(beatBytes) { Mem(endAddressHi, UInt(width = countBits)) } val dec_bytes = Seq.fill(beatBytes) { Mem(endAddressHi, UInt(width = countBits)) } val inc_trees = Seq.tabulate(decTrees) { i => Mem(endAddressHi >> (i+1), UInt(width = countBits)) } val dec_trees = Seq.tabulate(decTrees) { i => Mem(endAddressHi >> (i+1), UInt(width = countBits)) } - - // Don't care on power-up + + val shadow_wen = Wire(init = Fill(beatBytes, wipe)) + val inc_bytes_wen = Wire(init = Fill(beatBytes, wipe)) + val dec_bytes_wen = Wire(init = Fill(beatBytes, wipe)) + val inc_trees_wen = Wire(init = Fill(decTrees, wipe)) + val dec_trees_wen = Wire(init = Fill(decTrees, wipe)) + + // Don't care on power-up !!! Mem ? val flight = Reg(Vec(endSourceId, new FlightMonitor)) // Process A access requests - val a = RegNext(io.in(0).a) - val a_beats1 = edge.numBeats1(a.bits) - val a_size = edge.size(a.bits) + val a = Reg(next = in.a.bits) + val a_fire = Reg(next = in.a.fire(), init = Bool(false)) + val a_beats1 = edge.numBeats1(a) + val a_size = edge.size(a) val a_sizeOH = UIntToOH(a_size) val a_counter = RegInit(UInt(0, width = maxLgBeats)) val a_counter1 = a_counter - UInt(1) val a_first = a_counter === UInt(0) - val a_addr_hi = a.bits.addr_hi | (a_beats1 & ~a_counter1) - val a_base = edge.address(a.bits) + val a_addr_hi = a.addr_hi | (a_beats1 & ~a_counter1) + val a_base = edge.address(a) val a_mask = edge.mask(a_base, a_size) // What is the request? val a_flight = Wire(new FlightMonitor) a_flight.base := a_base a_flight.size := a_size - a_flight.opcode := a.bits.opcode + a_flight.opcode := a.opcode // Grab the concurrency state we need val a_inc_bytes = inc_bytes.map(_.read(a_addr_hi)) @@ -80,56 +108,72 @@ class TLRAMModel extends LazyModule val a_inc = a_inc_bytes.map(_ + a_inc_tree) val a_dec = a_dec_bytes.map(_ + a_dec_tree) - when (a.fire()) { + when (a_fire) { // Record the request so we can handle it's response - flight(a.bits.source) := a_flight + flight(a.source) := a_flight a_counter := Mux(a_first, a_beats1, a_counter1) // !!! atomics - assert (a.bits.opcode =/= TLMessages.Acquire) + assert (a.opcode =/= TLMessages.Acquire) // Increase the per-byte flight counter for the whole transaction - when (a_first && a.bits.opcode =/= TLMessages.Hint) { + when (a_first && a.opcode =/= TLMessages.Hint) { when (a_size <= UInt(shift)) { - for (i <- 0 until beatBytes) { - when (a_mask(i)) { // not a.bits.mask; the full mask - inc_bytes(i).write(a_addr_hi, a_inc_bytes(i) + UInt(1)) - } - } - } - for (i <- 0 until inc_trees.size) { - when (a_sizeOH(i+shift+1)) { - inc_trees(i).write(a_addr_hi >> (i+1), a_inc_trees(i) + UInt(1)) - } + inc_bytes_wen := a_mask } + inc_trees_wen := a_sizeOH >> (shift+1) } - when (a.bits.opcode === TLMessages.PutFullData || a.bits.opcode === TLMessages.PutPartialData) { + when (a.opcode === TLMessages.PutFullData || a.opcode === TLMessages.PutPartialData) { + shadow_wen := a.mask for (i <- 0 until beatBytes) { - val set = Wire(new ByteMonitor) val busy = a_inc(i) - a_dec(i) - (!a_first).asUInt - set.valid := busy === UInt(0) - set.value := a.bits.data(8*(i+1)-1, 8*i) - when (a.bits.mask(i)) { - shadow(i).write(a_addr_hi, set) - printf("P 0x%x := 0x%x #%d\n", a_addr_hi << shift | UInt(i), set.value, busy) + val byte = a.data(8*(i+1)-1, 8*i) + when (a.mask(i)) { + printf("P 0x%x := 0x%x #%d\n", a_addr_hi << shift | UInt(i), byte, busy) } } } } + val a_waddr = Mux(wipe, wipeIndex, a_addr_hi) + for (i <- 0 until beatBytes) { + val data = Wire(new ByteMonitor) + val busy = a_inc(i) - a_dec(i) - (!a_first).asUInt + data.valid := Mux(wipe, Bool(false), busy === UInt(0)) + data.value := a.data(8*(i+1)-1, 8*i) + when (shadow_wen(i)) { + shadow(i).write(a_waddr, data) + } + } + + for (i <- 0 until beatBytes) { + val data = Mux(wipe, UInt(0), a_inc_bytes(i) + UInt(1)) + when (inc_bytes_wen(i)) { + inc_bytes(i).write(a_waddr, data) + } + } + + for (i <- 0 until inc_trees.size) { + val data = Mux(wipe, UInt(0), a_inc_trees(i) + UInt(1)) + when (inc_trees_wen(i)) { + inc_trees(i).write(a_waddr >> (i+1), data) + } + } + // Process D access responses - val d = RegNext(io.out(0).d) - val d_bypass = a.valid && d.bits.source === a.bits.source - val d_flight = Mux(d_bypass, a_flight, flight(d.bits.source)) - val d_beats1 = edge.numBeats1(d.bits) - val d_size = edge.size(d.bits) + val d = RegNext(out.d.bits) + val d_fire = Reg(next = out.d.fire(), init = Bool(false)) + val d_bypass = a_fire && d.source === a.source + val d_flight = Mux(d_bypass, a_flight, flight(d.source)) + val d_beats1 = edge.numBeats1(d) + val d_size = edge.size(d) val d_sizeOH = UIntToOH(d_size) val d_counter = RegInit(UInt(0, width = maxLgBeats)) val d_counter1 = d_counter - UInt(1) val d_first = d_counter === UInt(0) val d_last = d_counter === UInt(1) || d_beats1 === UInt(0) - val d_base = d_flight.base + val d_base = d_flight.base // !!! not a register => can't be absorbed val d_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1) val d_mask = edge.mask(d_base, d_size) @@ -144,44 +188,36 @@ class TLRAMModel extends LazyModule val d_dec = d_dec_bytes.map(_ + d_dec_tree) val d_shadow = shadow.map(_.read(d_addr_hi)) - when (d.fire()) { + when (d_fire) { assert (d_size === d_flight.size) d_counter := Mux(d_first, d_beats1, d_counter1) when (d_flight.opcode === TLMessages.Hint) { - assert (d.bits.opcode === TLMessages.HintAck) + assert (d.opcode === TLMessages.HintAck) } // Decreaes the per-byte flight counter for the whole transaction when (d_last && d_flight.opcode =/= TLMessages.Hint) { when (d_size <= UInt(shift)) { - for (i <- 0 until beatBytes) { - when (d_mask(i)) { - dec_bytes(i).write(d_addr_hi, d_dec_bytes(i) + UInt(1)) - } - } - } - for (i <- 0 until dec_trees.size) { - when (d_sizeOH(i+shift+1)) { - dec_trees(i).write(d_addr_hi >> (i+1), d_dec_trees(i) + UInt(1)) - } + dec_bytes_wen := d_mask } + dec_trees_wen := d_sizeOH >> (shift+1) } when (d_flight.opcode === TLMessages.PutFullData || d_flight.opcode === TLMessages.PutPartialData) { - assert (d.bits.opcode === TLMessages.AccessAck) + assert (d.opcode === TLMessages.AccessAck) } // !!! atomics when (d_flight.opcode === TLMessages.Get) { - assert (d.bits.opcode === TLMessages.AccessAckData) + assert (d.opcode === TLMessages.AccessAckData) for (i <- 0 until beatBytes) { - val got = d.bits.data(8*(i+1)-1, 8*i) + val got = d.data(8*(i+1)-1, 8*i) val shadow = Wire(init = d_shadow(i)) when (d_mask(i)) { when (!shadow.valid) { - printf("G 0x%x := undefined due to concurrent accesses\n", d_addr_hi << shift | UInt(i)) + printf("G 0x%x := undefined\n", d_addr_hi << shift | UInt(i)) } .otherwise { printf("G 0x%x := 0x%x\n", d_addr_hi << shift | UInt(i), shadow.value) assert (shadow.value === got) @@ -190,5 +226,20 @@ class TLRAMModel extends LazyModule } } } + + val d_waddr = Mux(wipe, wipeIndex, d_addr_hi) + for (i <- 0 until beatBytes) { + val data = Mux(wipe, UInt(0), d_dec_bytes(i) + UInt(1)) + when (dec_bytes_wen(i)) { + dec_bytes(i).write(d_waddr, data) + } + } + + for (i <- 0 until dec_trees.size) { + val data = Mux(wipe, UInt(0), d_dec_trees(i) + UInt(1)) + when (dec_trees_wen(i)) { + dec_trees(i).write(d_waddr >> (i+1), data) + } + } } } From 26f9e2dfbd68a2503624b7915b594f4d0ae01307 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sat, 10 Sep 2016 01:22:12 -0700 Subject: [PATCH 06/24] tilelink2 Parameters: fix width=1 address truncation bug --- src/main/scala/uncore/tilelink2/Parameters.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 82e0500a..4bda7612 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -322,7 +322,7 @@ case class TLEdgeParameters( require (maxTransfer >= manager.beatBytes) val bundle = TLBundleParameters( - addrHiBits = log2Up(manager.maxAddress + 1) - log2Up(manager.beatBytes), + addrHiBits = log2Up(manager.maxAddress + 1) - log2Ceil(manager.beatBytes), dataBits = manager.beatBytes * 8, sourceBits = log2Up(client.endSourceId), sinkBits = log2Up(manager.endSinkId), From 9560df537c2f2b37561fe643d42573f0dd70d64c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 11 Sep 2016 15:43:04 -0700 Subject: [PATCH 07/24] tilelink2 RegisterRouter: allow sub-4k devices in order to make useful unit tests --- src/main/scala/uncore/tilelink2/RegisterRouter.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala index a3b61da7..ce46fc11 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouter.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouter.scala @@ -105,9 +105,8 @@ class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp] (moduleBuilder: (=> B, TLRegisterRouterBase) => M) extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes) { - require (size % 4096 == 0) // devices should be 4K aligned require (isPow2(size)) - require (size >= 4096) + // require (size >= 4096) ... not absolutely required, but highly recommended lazy val module = moduleBuilder(bundleBuilder(TLRegBundleArg(intnode.bundleOut, node.bundleIn)), this) } From 85ae77c108588fcce16498dd730527cfa7d63cff Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 11 Sep 2016 15:44:56 -0700 Subject: [PATCH 08/24] tilelink2 RAMModule: carefully stage the pipeline to make BRAMs possible --- .../scala/uncore/tilelink2/RAMModel.scala | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RAMModel.scala b/src/main/scala/uncore/tilelink2/RAMModel.scala index e85bd5d4..45172b3a 100644 --- a/src/main/scala/uncore/tilelink2/RAMModel.scala +++ b/src/main/scala/uncore/tilelink2/RAMModel.scala @@ -15,7 +15,8 @@ class TLRAMModel extends LazyModule val out = node.bundleOut } - require (io.out.size == 1) // !!! support multiple clients + // !!! support multiple clients via clock division + require (io.out.size == 1) val in = io.in(0) val out = io.out(0) @@ -64,6 +65,7 @@ class TLRAMModel extends LazyModule val opcode = UInt(width = 3) } + // Infer as simple dual port BRAM/M10k with write-first/new-data semantics (bypass needed) val shadow = Seq.fill(beatBytes) { Mem(endAddressHi, new ByteMonitor) } val inc_bytes = Seq.fill(beatBytes) { Mem(endAddressHi, UInt(width = countBits)) } val dec_bytes = Seq.fill(beatBytes) { Mem(endAddressHi, UInt(width = countBits)) } @@ -76,8 +78,18 @@ class TLRAMModel extends LazyModule val inc_trees_wen = Wire(init = Fill(decTrees, wipe)) val dec_trees_wen = Wire(init = Fill(decTrees, wipe)) - // Don't care on power-up !!! Mem ? - val flight = Reg(Vec(endSourceId, new FlightMonitor)) + // This requires either distributed memory or registers (no register on either input or output) + val flight = Mem(endSourceId, new FlightMonitor) + + // We want to cross flight data from A to D in the same cycle (for combinational TL2 devices) + val a_flight = Wire(new FlightMonitor) + a_flight.base := edge.address(in.a.bits) + a_flight.size := edge.size(in.a.bits) + a_flight.opcode := in.a.bits.opcode + + flight.write(in.a.bits.source, a_flight) + val bypass = in.a.valid && in.a.bits.source === out.d.bits.source + val d_flight = RegNext(Mux(bypass, a_flight, flight.read(out.d.bits.source))) // Process A access requests val a = Reg(next = in.a.bits) @@ -92,12 +104,6 @@ class TLRAMModel extends LazyModule val a_base = edge.address(a) val a_mask = edge.mask(a_base, a_size) - // What is the request? - val a_flight = Wire(new FlightMonitor) - a_flight.base := a_base - a_flight.size := a_size - a_flight.opcode := a.opcode - // Grab the concurrency state we need val a_inc_bytes = inc_bytes.map(_.read(a_addr_hi)) val a_dec_bytes = dec_bytes.map(_.read(a_addr_hi)) @@ -110,7 +116,6 @@ class TLRAMModel extends LazyModule when (a_fire) { // Record the request so we can handle it's response - flight(a.source) := a_flight a_counter := Mux(a_first, a_beats1, a_counter1) // !!! atomics @@ -165,7 +170,6 @@ class TLRAMModel extends LazyModule val d = RegNext(out.d.bits) val d_fire = Reg(next = out.d.fire(), init = Bool(false)) val d_bypass = a_fire && d.source === a.source - val d_flight = Mux(d_bypass, a_flight, flight(d.source)) val d_beats1 = edge.numBeats1(d) val d_size = edge.size(d) val d_sizeOH = UIntToOH(d_size) @@ -173,7 +177,7 @@ class TLRAMModel extends LazyModule val d_counter1 = d_counter - UInt(1) val d_first = d_counter === UInt(0) val d_last = d_counter === UInt(1) || d_beats1 === UInt(0) - val d_base = d_flight.base // !!! not a register => can't be absorbed + val d_base = d_flight.base val d_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1) val d_mask = edge.mask(d_base, d_size) From 7760459b761a2f51f250af9d066ba49c92f90fd7 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 00:22:04 -0700 Subject: [PATCH 09/24] tilelink2 RegisterRouter: add RegField test patterns --- .../uncore/tilelink2/RegisterRouterTest.scala | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/main/scala/uncore/tilelink2/RegisterRouterTest.scala diff --git a/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala b/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala new file mode 100644 index 00000000..a93112f5 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala @@ -0,0 +1,142 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +object LFSR16Seed +{ + def apply(seed: Int): UInt = + { + val width = 16 + val lfsr = Reg(init=UInt(seed, width)) + lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) + lfsr + } +} + +class RRTestCombinational(val bits: Int, rvalid: Bool => Bool, wready: Bool => Bool) extends Module +{ + val io = new Bundle { + val rvalid = Bool(OUTPUT) + val rready = Bool(INPUT) + val rdata = UInt(OUTPUT, width = bits) + val wvalid = Bool(INPUT) + val wready = Bool(OUTPUT) + val wdata = UInt(INPUT, width = bits) + } + + val rfire = io.rvalid && io.rready + val wfire = io.wvalid && io.wready + val reg = Reg(UInt(width = bits)) + + io.rvalid := rvalid(rfire) + io.wready := wready(wfire) + + io.rdata := Mux(rfire, reg, UInt(0)) + when (wfire) { reg := io.wdata } +} + +object RRTestCombinational +{ + private var seed = 0 + def always: Bool => Bool = _ => Bool(true) + def random: Bool => Bool = { + seed = seed + 1 + val lfsr = LFSR16Seed(seed) + _ => lfsr(0) + } + def delay(x: Int): Bool => Bool = { fire => + val reg = RegInit(UInt(0, width = log2Ceil(x+1))) + val ready = reg === UInt(0) + reg := Mux(fire, UInt(x), Mux(ready, UInt(0), reg - UInt(1))) + ready + } + + def combo(bits: Int, rvalid: Bool => Bool, wready: Bool => Bool): RegField = { + val combo = Module(new RRTestCombinational(bits, rvalid, wready)) + RegField(bits, + RegReadFn { ready => combo.io.rready := ready; (combo.io.rvalid, combo.io.rdata) }, + RegWriteFn { (valid, data) => combo.io.wvalid := valid; combo.io.wdata := data; combo.io.wready }) + } +} + +class RRTestRequest(val bits: Int, + rflow: (Bool, Bool, UInt) => (Bool, Bool, UInt), + wflow: (Bool, Bool, UInt) => (Bool, Bool, UInt)) extends Module +{ + val io = new Bundle { + val rivalid = Bool(INPUT) + val riready = Bool(OUTPUT) + val rovalid = Bool(OUTPUT) + val roready = Bool(INPUT) + val rdata = UInt(OUTPUT, width = bits) + val wivalid = Bool(INPUT) + val wiready = Bool(OUTPUT) + val wovalid = Bool(OUTPUT) + val woready = Bool(INPUT) + val wdata = UInt(INPUT, width = bits) + } + + val (riready, rovalid, _) = rflow(io.rivalid, io.roready, UInt(0, width = 1)) + val (wiready, wovalid, wdata) = wflow(io.wivalid, io.woready, io.wdata) + val reg = Reg(UInt(width = bits)) + + io.riready := riready + io.rovalid := rovalid + io.wiready := wiready + io.wovalid := wovalid + + val rofire = io.roready && rovalid + val wofire = io.woready && wovalid + + io.rdata := Mux(rofire, reg, UInt(0)) + when (wofire) { reg := wdata } +} + +object RRTestRequest +{ + private var seed = 0 + def pipe(x: Int): (Bool, Bool, UInt) => (Bool, Bool, UInt) = { (ivalid, oready, idata) => + val full = RegInit(Vec.fill(x)(Bool(false))) + val ready = Wire(Vec.fill(x)(Bool())) + val data = Reg(Vec.fill(x)(UInt(width = idata.getWidth))) + // Construct a classic bubble-filling pipeline + ready(x) := oready || !full(x) + when (ready(0)) { data(0) := idata } + ((ready.init zip ready.tail) zip full.init) foreach { case ((self, next), full) => + self := next || !full + } + ((data.init zip data.tail) zip ready.tail) foreach { case ((prev, self), ready) => + when (ready) { self := prev } + } + (ready(0), full(x), Mux(full(x) && oready, data(x), UInt(0))) + } + def busy: (Bool, Bool, UInt) => (Bool, Bool, UInt) = { + seed = seed + 1 + val lfsr = LFSR16Seed(seed) + (ivalid, oready, idata) => { + val busy = RegInit(Bool(false)) + val progress = lfsr(0) + when (progress) { + busy := Mux(busy, !oready, ivalid) + } + (progress && !busy, progress && busy, idata) + } + } + def request(bits: Int, + rflow: (Bool, Bool, UInt) => (Bool, Bool, UInt), + wflow: (Bool, Bool, UInt) => (Bool, Bool, UInt)): RegField = { + val request = Module(new RRTestRequest(bits, rflow, wflow)) + RegField(bits, + RegReadFn { (rivalid, roready) => + request.io.rivalid := rivalid + request.io.roready := roready + (request.io.riready, request.io.rovalid, request.io.rdata) }, + RegWriteFn { (wivalid, woready, wdata) => + request.io.wivalid := wivalid + request.io.woready := woready + request.io.wdata := wdata + (request.io.wiready, request.io.wovalid) }) + } +} From 0671d5d637fbf3ca74ee842875a9c9b3ea1124ff Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Fri, 9 Sep 2016 17:16:35 -0700 Subject: [PATCH 10/24] Initial version of fuzzer and simple ram fuzz test --- chisel3 | 2 +- .../scala/junctions/unittests/UnitTest.scala | 4 +- src/main/scala/uncore/tilelink2/Fuzzer.scala | 145 ++++++++++++++++++ src/main/scala/uncore/unittests/Tests.scala | 3 +- 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 src/main/scala/uncore/tilelink2/Fuzzer.scala diff --git a/chisel3 b/chisel3 index 16426b3a..bb240453 160000 --- a/chisel3 +++ b/chisel3 @@ -1 +1 @@ -Subproject commit 16426b3a68d85ce7dd9655b0ce773431eb69fc74 +Subproject commit bb240453abf96b4c2d75ebb2cdc7e3159068431d diff --git a/src/main/scala/junctions/unittests/UnitTest.scala b/src/main/scala/junctions/unittests/UnitTest.scala index f206e945..b40be2af 100644 --- a/src/main/scala/junctions/unittests/UnitTest.scala +++ b/src/main/scala/junctions/unittests/UnitTest.scala @@ -4,12 +4,14 @@ import Chisel._ import junctions._ import cde.{Field, Parameters} -abstract class UnitTest extends Module { +trait HasUnitTestIO { val io = new Bundle { val finished = Bool(OUTPUT) val start = Bool(INPUT) } +} +abstract class UnitTest extends Module with HasUnitTestIO { when (io.start) { printf(s"Started UnitTest ${this.getClass.getSimpleName}\n") } diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala new file mode 100644 index 00000000..f39ff722 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -0,0 +1,145 @@ +// See LICENSE for license details. +package uncore.tilelink2 + +import Chisel._ +import chisel3.util.LFSR16 +import junctions.unittests._ + +object LFSR64 +{ + private var counter = 0 + private def next: Int = { + counter += 1 + counter + } + + def apply(increment: Bool = Bool(true), seed: Int = next): UInt = + { + val wide = 64 + val lfsr = RegInit(UInt((seed * 0xDEADBEEFCAFEBAB1L) >>> 1, width = wide)) + val xor = lfsr(0) ^ lfsr(1) ^ lfsr(3) ^ lfsr(4) + when (increment) { lfsr := Cat(xor, lfsr(wide-1,1)) } + lfsr + } +} + +object NoiseMaker +{ + def apply(wide: Int, increment: Bool = Bool(true)): UInt = { + val lfsrs = Seq.fill((wide+63)/64) { LFSR64(increment) } + Cat(lfsrs)(wide-1,0) + } +} + +object MaskMaker +{ + def apply(wide: Int, bits: UInt): UInt = + Vec.tabulate(wide) {UInt(_) < bits} .asUInt +} + + +class TLFuzzer(nOperations: Int) extends LazyModule +{ + val node = TLClientNode(TLClientParameters()) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val out = node.bundleOut + val finished = Bool() + } + + val out = io.out(0) + val edge = node.edgesOut(0) + + val idx = Reg(init = UInt(nOperations-1, log2Up(nOperations))) + val finished = RegInit(Bool(false)) + val valid = RegInit(Bool(false)) + valid := Bool(true) + io.finished := finished + + val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) + val inc = Wire(Bool()) + + val addrBits = log2Up(edge.manager.maxAddress + 1) + val amo_size = UInt(2) + NoiseMaker(1, inc) // word or dword + val size = NoiseMaker(edge.bundle.sizeBits, inc) + val addr_mask = MaskMaker(addrBits, size) + val addr = NoiseMaker(addrBits, inc) & ~addr_mask + val wmask = NoiseMaker(edge.manager.beatBytes, inc) + val data = NoiseMaker(edge.bundle.dataBits, inc) + val arth_op = NoiseMaker(3, inc) + val log_op = NoiseMaker(2, inc) + val src = UInt(0) + + val (glegal, gbits) = edge.Get(src, addr, size) + val (pflegal, pfbits) = if(edge.manager.anySupportPutFull) { + edge.Put(src, addr, size, data) + } else { (glegal, gbits) } + val (pplegal, ppbits) = if(edge.manager.anySupportPutPartial) { + edge.Put(src, addr, size, data, wmask) + } else { (glegal, gbits) } + val (alegal, abits) = if(edge.manager.anySupportArithmetic) { + edge.Arithmetic(src, addr, size, data, arth_op) + } else { (glegal, gbits) } + val (llegal, lbits) = if(edge.manager.anySupportLogical) { + edge.Logical(src, addr, size, data, log_op) + } else { (glegal, gbits) } + val (hlegal, hbits) = if(edge.manager.anySupportHint) { + edge.Hint(src, addr, size, UInt(0)) + } else { (glegal, gbits) } + + val a_type_sel = NoiseMaker(3, inc) + + val legal = MuxLookup(a_type_sel, glegal, Seq( + UInt("b000") -> glegal, + UInt("b001") -> pflegal, + UInt("b010") -> pplegal, + UInt("b011") -> alegal, + UInt("b100") -> llegal, + UInt("b101") -> hlegal)) + + val bits = MuxLookup(a_type_sel, gbits, Seq( + UInt("b000") -> gbits, + UInt("b001") -> pfbits, + UInt("b010") -> ppbits, + UInt("b011") -> abits, + UInt("b100") -> lbits, + UInt("b101") -> hbits)) + + out.a.valid := legal + out.a.bits := bits + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.d.ready := Bool(true) + out.e.valid := Bool(false) + + inc := !legal || (out.a.fire() && counter === UInt(0)) + when (out.a.fire()) { + counter := counter - UInt(1) + when (counter === UInt(0)) { + counter := edge.numBeats(out.a.bits) - UInt(1) + idx := idx - UInt(1) + } + when (idx === UInt(0)) { finished := Bool(true) } + } + } +} + +class TLFuzzRAM extends LazyModule +{ + val ram = LazyModule(new TLRAM(AddressSet(0, 0xfff))) + val xbar = LazyModule(new TLXbar) + val fuzz = LazyModule(new TLFuzzer(1000)) + + connect(TLWidthWidget(TLHintHandler(fuzz.node), 16) -> xbar.node) + connect(TLFragmenter(TLBuffer(xbar.node), 4, 256) -> ram.node) + + lazy val module = new LazyModuleImp(this) with HasUnitTestIO { + io.finished := fuzz.module.io.finished + } +} + +class TLFuzzRAMTest extends UnitTest { + val dut = LazyModule(new TLFuzzRAM).module + io.finished := dut.io.finished +} diff --git a/src/main/scala/uncore/unittests/Tests.scala b/src/main/scala/uncore/unittests/Tests.scala index bcd9de37..c59194b6 100644 --- a/src/main/scala/uncore/unittests/Tests.scala +++ b/src/main/scala/uncore/unittests/Tests.scala @@ -81,5 +81,6 @@ object UncoreUnitTests { Seq( Module(new SmiConverterTest), Module(new ROMSlaveTest), - Module(new TileLinkRAMTest)) + Module(new TileLinkRAMTest), + Module(new uncore.tilelink2.TLFuzzRAMTest)) } From a21b04a7c1204d94fc7157b27403ea56203d8b2c Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Fri, 9 Sep 2016 17:19:03 -0700 Subject: [PATCH 11/24] playground for making different DAGs to use as DUTs --- .../scala/uncore/tilelink2/TestGraphs.scala | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/main/scala/uncore/tilelink2/TestGraphs.scala diff --git a/src/main/scala/uncore/tilelink2/TestGraphs.scala b/src/main/scala/uncore/tilelink2/TestGraphs.scala new file mode 100644 index 00000000..169a82d1 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/TestGraphs.scala @@ -0,0 +1,92 @@ +// See LICENSE for license details. +package uncore.tilelink2 + +import Chisel._ +import chisel3.util.LFSR16 +import junctions.unittests._ + +class TLClient extends LazyModule +{ + val node = TLClientNode(TLClientParameters()) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val out = node.bundleOut + val finished = Bool() + } + + require (node.edgesOut(0).manager.beatBytes == 16) + + val addr = RegInit(UInt(0, width = 13)) + val size = RegInit(UInt(0, width = 4)) + val put = RegInit(Bool(false)) + val width = 12 + val count = RegInit(UInt(0, width = width)) + val limit = ~(SInt(-1, width=width).asUInt << size)(width-1, 0) >> 4 + + val out = io.out(0) + val edge = node.edgesOut(0) + val data = Cat(Seq.tabulate(16) { i => UInt(i) | (count(3,0) + UInt(1)) << 4 } .reverse) + + val (legalg, gbits) = edge.Get(UInt(0), addr, size) + val (legalp, pbits) = edge.Put(UInt(0), addr, size, data) + val legal = Mux(put, legalp, legalg) + val bits = Mux(put, pbits, gbits) + + out.a.valid := legal + out.a.bits := bits + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.d.ready := Bool(true) + out.e.valid := Bool(false) + io.finished := Bool(true)//count === limit + + when (out.a.fire()) { count := count + UInt(1) } + when (!legal || (out.a.fire() && Mux(put, count === limit, Bool(true)))) { + count := UInt(0) + size := size + UInt(1) + put := LFSR16()(0) + addr := addr + UInt(0x100) + when (size === UInt(8)) { size := UInt(0) } + } + } +} + +class Bar extends LazyModule +{ + val node = TLOutputNode() + + val client = LazyModule(new TLClient) + val xbar = LazyModule(new TLXbar) + + connect(client.node -> xbar.node) + connect(xbar.node -> node) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val out = node.bundleOut + val finished = Bool() + } + io.finished := client.module.io.finished + } +} + +class TLXbarGPIORAM extends LazyModule +{ + val ram = LazyModule(new TLRAM(AddressSet(0, 0xfff))) + val xbar = LazyModule(new TLXbar) + val bar = LazyModule(new Bar) + + connect(TLWidthWidget(TLHintHandler(bar.node), 16) -> xbar.node) + connect(TLFragmenter(TLBuffer(xbar.node), 4, 256) -> ram.node) + + lazy val module = new LazyModuleImp(this) with HasUnitTestIO { + io.finished := bar.module.io.finished + } +} + +class TLXbarGPIORAMTest extends UnitTest { + val dut = LazyModule(new TLXbarGPIORAM).module + io.finished := dut.io.finished +} + From 82681179cb051dd32a76e10b4f795ecbddfeda57 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Mon, 12 Sep 2016 14:00:00 -0700 Subject: [PATCH 12/24] [tilelink2] Edges: add size to addr_lo. addr_lo cannot correctly be deciphered from the mask alone. OxC still has addr_lo === 0 if size is >1. --- src/main/scala/uncore/tilelink2/Edges.scala | 24 +++++++++++++++---- src/main/scala/uncore/tilelink2/Monitor.scala | 4 ++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index a9993e65..1c74e840 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -47,7 +47,9 @@ class TLEdge( Cat(helper(lgBytes).map(_._1).reverse) } - def addr_lo(mask: UInt): UInt = { + // !!! make sure to align addr_lo for PutPartials with 0 masks + def addr_lo(mask: UInt, lgSize: UInt): UInt = { + val sizeOH1 = UIntToOH1(lgSize, log2Up(manager.beatBytes)) // Almost OHToUInt, but bits set => bits not set def helper(mask: UInt, width: Int): UInt = { if (width <= 1) { @@ -61,7 +63,11 @@ class TLEdge( Cat(!lo.orR, helper(hi | lo, mid)) } } - helper(mask, bundle.dataBits/8) + helper(mask, bundle.dataBits/8) & ~sizeOH1 + } + + def full_mask(imask: UInt, lgSize: UInt): UInt = { + mask(addr_lo(imask, lgSize), lgSize) } def staticHasData(bundle: TLChannel): Option[Boolean] = { @@ -167,13 +173,22 @@ class TLEdge( def addr_lo(x: TLDataChannel): UInt = { x match { - case a: TLBundleA => addr_lo(a.mask) - case b: TLBundleB => addr_lo(b.mask) + case a: TLBundleA => addr_lo(a.mask, a.size) + case b: TLBundleB => addr_lo(b.mask, b.size) case c: TLBundleC => c.addr_lo case d: TLBundleD => d.addr_lo } } + def full_mask(x: TLDataChannel): UInt = { + x match { + case a: TLBundleA => full_mask(a.mask, a.size) + case b: TLBundleB => full_mask(b.mask, b.size) + case c: TLBundleC => mask(c.addr_lo, c.size) + case d: TLBundleD => mask(d.addr_lo, d.size) + } + } + def address(x: TLAddrChannel): UInt = { val hi = x match { case a: TLBundleA => a.addr_hi @@ -600,6 +615,7 @@ class TLEdgeIn( d } + // !!! buggy! deduce sink from address def HintAck(a: TLBundleA, sink: UInt = UInt(0)): TLBundleD = HintAck(address(a), sink, a.source, a.size) def HintAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt) = { val d = Wire(new TLBundleD(bundle)) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index a74a6c20..3a0b83a0 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -20,7 +20,7 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) - val mask = edge.mask(edge.addr_lo(bundle.mask), bundle.size) + val mask = edge.full_mask(bundle) when (bundle.opcode === TLMessages.Acquire) { assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra) @@ -86,7 +86,7 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val address_ok = edge.manager.contains(bundle.source) val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) - val mask = edge.mask(edge.addr_lo(bundle.mask), bundle.size) + val mask = edge.full_mask(bundle) when (bundle.opcode === TLMessages.Probe) { assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client" + extra) From c57b52ec86ca8866e25fe6b2688aa36a2fcb05d1 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Mon, 12 Sep 2016 16:40:15 -0700 Subject: [PATCH 13/24] tilelink2 Fragmenter: bugfix using D.hasData --- src/main/scala/uncore/tilelink2/Fragmenter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index aa0efc5e..9a21c0f9 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -163,7 +163,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten } // Swallow up non-data ack fragments - val drop = (out.d.bits.opcode === TLMessages.AccessAck) && (dFragnum =/= UInt(0)) + val drop = !dHasData && (dFragnum =/= UInt(0)) out.d.ready := in.d.ready || drop in.d.valid := out.d.valid && !drop in.d.bits := out.d.bits // pass most stuff unchanged From 0b0c8911798e8ddad9054f323ac7181db95954ed Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Mon, 12 Sep 2016 15:31:26 -0700 Subject: [PATCH 14/24] [tilelink2] Monitor: Allow zero-mask PutPartials this will require a larger address refactoring TBD --- src/main/scala/uncore/tilelink2/Monitor.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 3a0b83a0..d84425ae 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -53,7 +53,6 @@ object TLMonitor assert (is_aligned, "'A' channel PutPartial address not aligned to size" + extra) assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param" + extra) assert ((bundle.mask & ~mask) === UInt(0), "'A' channel PutPartial contains invalid mask" + extra) - assert (bundle.mask =/= UInt(0), "'A' channel PutPartial has a zero mask" + extra) } when (bundle.opcode === TLMessages.ArithmeticData) { @@ -119,7 +118,6 @@ object TLMonitor assert (is_aligned, "'B' channel PutPartial address not aligned to size" + extra) assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param" + extra) assert ((bundle.mask & ~mask) === UInt(0), "'B' channel PutPartial contains invalid mask" + extra) - assert (bundle.mask =/= UInt(0), "'B' channel PutPartial has a zero mask" + extra) } when (bundle.opcode === TLMessages.ArithmeticData) { From ad8e563c89d55d921c5fe377cdd8264aab76d32e Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Mon, 12 Sep 2016 16:55:29 -0700 Subject: [PATCH 15/24] [tilelink2] Fuzzer: Rewrite of fuzzer Multiple bug-fixes and actual source id generation. --- src/main/scala/uncore/tilelink2/Fuzzer.scala | 125 +++++++++++++------ 1 file changed, 89 insertions(+), 36 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index f39ff722..8cda783e 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -5,6 +5,33 @@ import Chisel._ import chisel3.util.LFSR16 import junctions.unittests._ +class IDMapGenerator(numIds: Int) extends Module { + val w = log2Up(numIds) + val io = new Bundle { + val free = Decoupled(UInt(width = w)).flip + val alloc = Decoupled(UInt(width = w)) + } + + // True indicates that the id is available + val bitmap = RegInit(Vec.fill(numIds){Bool(true)}) + + io.free.ready := Bool(true) + assert(!io.free.valid || !bitmap(io.free.bits)) // No double freeing + + val mask = bitmap.scanLeft(Bool(false))(_||_).init + val select = mask zip bitmap map { case(m,b) => !m && b } + io.alloc.bits := OHToUInt(select) + io.alloc.valid := bitmap.reduce(_||_) + + when (io.alloc.fire()) { + bitmap(io.alloc.bits) := Bool(false) + } + + when (io.free.fire()) { + bitmap(io.free.bits) := Bool(true) + } +} + object LFSR64 { private var counter = 0 @@ -31,16 +58,9 @@ object NoiseMaker } } -object MaskMaker -{ - def apply(wide: Int, bits: UInt): UInt = - Vec.tabulate(wide) {UInt(_) < bits} .asUInt -} - - -class TLFuzzer(nOperations: Int) extends LazyModule +class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule { - val node = TLClientNode(TLClientParameters()) + val node = TLClientNode(TLClientParameters(sourceId = IdRange(0,inFlight))) lazy val module = new LazyModuleImp(this) { val io = new Bundle { @@ -50,33 +70,61 @@ class TLFuzzer(nOperations: Int) extends LazyModule val out = io.out(0) val edge = node.edgesOut(0) + val endAddress = edge.manager.maxAddress + 1 + val maxTransfer = edge.manager.maxTransfer + val beatBytes = edge.manager.beatBytes + val maxLgBeats = log2Up(maxTransfer/beatBytes) + val addressBits = log2Up(endAddress) + val sizeBits = edge.bundle.sizeBits + val dataBits = edge.bundle.dataBits - val idx = Reg(init = UInt(nOperations-1, log2Up(nOperations))) - val finished = RegInit(Bool(false)) - val valid = RegInit(Bool(false)) - valid := Bool(true) - io.finished := finished + // Progress through operations + val num_reqs = Reg(init = UInt(nOperations-1, log2Up(nOperations))) + val num_resps = Reg(init = UInt(nOperations-1, log2Up(nOperations))) + io.finished := num_resps =/= UInt(0) - val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) + // Progress within each operation + val a = out.a.bits + val a_beats1 = edge.numBeats1(a) + val a_counter = RegInit(UInt(0, width = maxLgBeats)) + val a_counter1 = a_counter - UInt(1) + val a_first = a_counter === UInt(0) + val a_last = a_counter === UInt(1) || a_beats1 === UInt(0) + val req_done = out.a.fire() && a_last + + val d = out.d.bits + val d_beats1 = edge.numBeats1(d) + val d_counter = RegInit(UInt(0, width = maxLgBeats)) + val d_counter1 = d_counter - UInt(1) + val d_first = d_counter === UInt(0) + val d_last = d_counter === UInt(1) || d_beats1 === UInt(0) + val resp_done = out.d.fire() && d_last + + // Source ID generation + val idMap = Module(new IDMapGenerator(inFlight)) + val alloc = Queue.irrevocable(idMap.io.alloc, 1, pipe = true) + val src = alloc.bits + alloc.ready := req_done + idMap.io.free.valid := resp_done + idMap.io.free.bits := out.d.bits.source + + // Increment random number generation for the following subfields val inc = Wire(Bool()) - - val addrBits = log2Up(edge.manager.maxAddress + 1) - val amo_size = UInt(2) + NoiseMaker(1, inc) // word or dword - val size = NoiseMaker(edge.bundle.sizeBits, inc) - val addr_mask = MaskMaker(addrBits, size) - val addr = NoiseMaker(addrBits, inc) & ~addr_mask - val wmask = NoiseMaker(edge.manager.beatBytes, inc) - val data = NoiseMaker(edge.bundle.dataBits, inc) + val inc_beat = Wire(Bool()) val arth_op = NoiseMaker(3, inc) val log_op = NoiseMaker(2, inc) - val src = UInt(0) + val amo_size = UInt(2) + NoiseMaker(1, inc) // word or dword + val size = NoiseMaker(sizeBits, inc) + val addr = NoiseMaker(addressBits, inc) & ~UIntToOH1(size, addressBits) + val mask = NoiseMaker(beatBytes, inc_beat) & edge.mask(addr, size) + val data = NoiseMaker(dataBits, inc_beat) val (glegal, gbits) = edge.Get(src, addr, size) val (pflegal, pfbits) = if(edge.manager.anySupportPutFull) { edge.Put(src, addr, size, data) } else { (glegal, gbits) } val (pplegal, ppbits) = if(edge.manager.anySupportPutPartial) { - edge.Put(src, addr, size, data, wmask) + edge.Put(src, addr, size, data, mask) } else { (glegal, gbits) } val (alegal, abits) = if(edge.manager.anySupportArithmetic) { edge.Arithmetic(src, addr, size, data, arth_op) @@ -106,33 +154,38 @@ class TLFuzzer(nOperations: Int) extends LazyModule UInt("b100") -> lbits, UInt("b101") -> hbits)) - out.a.valid := legal + out.a.valid := legal && alloc.valid && num_reqs =/= UInt(0) out.a.bits := bits out.b.ready := Bool(true) out.c.valid := Bool(false) out.d.ready := Bool(true) out.e.valid := Bool(false) - inc := !legal || (out.a.fire() && counter === UInt(0)) + inc := !legal || req_done + inc_beat := !legal || out.a.fire() + when (out.a.fire()) { - counter := counter - UInt(1) - when (counter === UInt(0)) { - counter := edge.numBeats(out.a.bits) - UInt(1) - idx := idx - UInt(1) - } - when (idx === UInt(0)) { finished := Bool(true) } + a_counter := Mux(a_first, a_beats1, a_counter1) + when(a_last) { num_reqs := num_reqs - UInt(1) } + } + + when (out.d.fire()) { + d_counter := Mux(d_first, d_beats1, d_counter1) + when(d_last) { num_resps := num_resps - UInt(1) } } } } class TLFuzzRAM extends LazyModule { + val model = LazyModule(new TLRAMModel) val ram = LazyModule(new TLRAM(AddressSet(0, 0xfff))) val xbar = LazyModule(new TLXbar) val fuzz = LazyModule(new TLFuzzer(1000)) - connect(TLWidthWidget(TLHintHandler(fuzz.node), 16) -> xbar.node) - connect(TLFragmenter(TLBuffer(xbar.node), 4, 256) -> ram.node) + model.node := fuzz.node + xbar.node := TLWidthWidget(model.node, 16) + ram.node := TLHintHandler(TLFragmenter(TLBuffer(xbar.node), 4, 256)) lazy val module = new LazyModuleImp(this) with HasUnitTestIO { io.finished := fuzz.module.io.finished @@ -140,6 +193,6 @@ class TLFuzzRAM extends LazyModule } class TLFuzzRAMTest extends UnitTest { - val dut = LazyModule(new TLFuzzRAM).module + val dut = Module(LazyModule(new TLFuzzRAM).module) io.finished := dut.io.finished } From ca5f98f138c0b8fb3292122821f086e1cbd4c323 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 17:15:28 -0700 Subject: [PATCH 16/24] tilelink2: Hints are not special Hints have a TransferSize limit just like all other message types. --- src/main/scala/uncore/tilelink2/Edges.scala | 4 ++-- .../scala/uncore/tilelink2/Fragmenter.scala | 2 +- .../scala/uncore/tilelink2/HintHandler.scala | 8 +++---- src/main/scala/uncore/tilelink2/Monitor.scala | 4 ++-- .../scala/uncore/tilelink2/Parameters.scala | 24 +++++++------------ 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 1c74e840..7b37c7cb 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -378,7 +378,7 @@ class TLEdgeOut( def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = { require (manager.anySupportHint) - val legal = manager.supportsHint(toAddress) + val legal = manager.supportsHint(toAddress, lgSize) val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.Hint a.param := param @@ -571,7 +571,7 @@ class TLEdgeIn( def Hint(fromAddress: UInt, toSource: UInt, lgSize: UInt, param: UInt) = { require (client.anySupportHint) - val legal = client.supportsHint(toSource) + val legal = client.supportsHint(toSource, lgSize) val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.Hint b.param := param diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 9a21c0f9..7495a8a3 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -44,7 +44,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten supportsGet = TransferSizes.none, supportsPutFull = TransferSizes.none, supportsPutPartial = TransferSizes.none, - supportsHint = false) + supportsHint = TransferSizes.none) val node = TLAdapterNode( clientFn = { case Seq(c) => c.copy(clients = c.clients.map(mapClient)) }, diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index b8938fbf..277297d5 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -9,8 +9,8 @@ import chisel3.internal.sourceinfo.SourceInfo class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends LazyModule { val node = TLAdapterNode( - clientFn = { case Seq(c) => if (supportClients) c.copy(clients = c.clients .map(_.copy(supportsHint = true))) else c }, - managerFn = { case Seq(m) => if (supportManagers) m.copy(managers = m.managers.map(_.copy(supportsHint = true))) else m }) + clientFn = { case Seq(c) => if (!supportClients) c else c.copy(clients = c.clients .map(_.copy(supportsHint = TransferSizes(1, c.maxTransfer)))) }, + managerFn = { case Seq(m) => if (!supportManagers) m else m.copy(managers = m.managers.map(_.copy(supportsHint = TransferSizes(1, m.maxTransfer)))) }) lazy val module = new LazyModuleImp(this) { val io = new Bundle { @@ -28,7 +28,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f require (!supportClients || bce) if (supportManagers) { - val handleA = if (passthrough) !edgeOut.manager.supportsHint(edgeIn.address(in.a.bits)) else Bool(true) + val handleA = if (passthrough) !edgeOut.manager.supportsHint(edgeIn.address(in.a.bits), edgeIn.size(in.a.bits)) else Bool(true) val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint // Prioritize existing D traffic over HintAck @@ -50,7 +50,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f } if (supportClients) { - val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source) else Bool(true) + val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true) val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint // Prioritize existing C traffic over HintAck diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index d84425ae..763ce04e 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -72,7 +72,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.Hint) { - assert (edge.manager.supportsHint(edge.address(bundle)), "'A' channel carries Hint type unsupported by manager" + extra) + assert (edge.manager.supportsHint(edge.address(bundle), bundle.size), "'A' channel carries Hint type unsupported by manager" + extra) assert (source_ok, "'A' channel Hint carries invalid source ID" + extra) assert (is_aligned, "'A' channel Hint address not aligned to size" + extra) assert (bundle.mask === mask, "'A' channel Hint contains invalid mask" + extra) @@ -137,7 +137,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.Hint) { - assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client" + extra) + assert (edge.client.supportsHint(bundle.source, bundle.size), "'B' channel carries Hint type unsupported by client" + extra) assert (address_ok, "'B' channel Hint carries unmanaged address" + extra) assert (is_aligned, "'B' channel Hint address not aligned to size" + extra) assert (bundle.mask === mask, "'B' channel Hint contains invalid mask" + extra) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 4bda7612..9648a3b5 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -110,7 +110,7 @@ case class TLManagerParameters( supportsGet: TransferSizes = TransferSizes.none, supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, - supportsHint: Boolean = false, + supportsHint: TransferSizes = TransferSizes.none, // If fifoId=Some, all accesses sent to the same fifoId are executed and ACK'd in FIFO order fifoId: Option[Int] = None) { @@ -159,7 +159,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes val allSupportGet = managers.map(_.supportsGet) .reduce(_ intersect _) val allSupportPutFull = managers.map(_.supportsPutFull) .reduce(_ intersect _) val allSupportPutPartial = managers.map(_.supportsPutPartial).reduce(_ intersect _) - val allSupportHint = managers.map(_.supportsHint) .reduce(_ && _) + val allSupportHint = managers.map(_.supportsHint) .reduce(_ intersect _) // Operation supported by at least one outward Managers val anySupportAcquire = managers.map(!_.supportsAcquire.none) .reduce(_ || _) @@ -168,7 +168,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes val anySupportGet = managers.map(!_.supportsGet.none) .reduce(_ || _) val anySupportPutFull = managers.map(!_.supportsPutFull.none) .reduce(_ || _) val anySupportPutPartial = managers.map(!_.supportsPutPartial.none).reduce(_ || _) - val anySupportHint = managers.map( _.supportsHint) .reduce(_ || _) + val anySupportHint = managers.map(!_.supportsHint.none) .reduce(_ || _) // These return Option[TLManagerParameters] for your convenience def find(address: BigInt) = managers.find(_.address.exists(_.contains(address))) @@ -198,11 +198,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes val supportsGet = safety_helper(_.supportsGet) _ val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ - def supportsHint(address: UInt) = { - if (allSupportHint) Bool(true) else { - Mux1H(find(address), managers.map(m => Bool(m.supportsHint))) - } - } + val supportsHint = safety_helper(_.supportsHint) _ } case class TLClientParameters( @@ -214,7 +210,7 @@ case class TLClientParameters( supportsGet: TransferSizes = TransferSizes.none, supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, - supportsHint: Boolean = false) + supportsHint: TransferSizes = TransferSizes.none) { require (supportsPutFull.contains(supportsPutPartial)) @@ -246,7 +242,7 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { val allSupportGet = clients.map(_.supportsGet) .reduce(_ intersect _) val allSupportPutFull = clients.map(_.supportsPutFull) .reduce(_ intersect _) val allSupportPutPartial = clients.map(_.supportsPutPartial).reduce(_ intersect _) - val allSupportHint = clients.map(_.supportsHint) .reduce(_ && _) + val allSupportHint = clients.map(_.supportsHint) .reduce(_ intersect _) // Operation is supported by at least one client val anySupportProbe = clients.map(!_.supportsProbe.none) .reduce(_ || _) @@ -255,7 +251,7 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { val anySupportGet = clients.map(!_.supportsGet.none) .reduce(_ || _) val anySupportPutFull = clients.map(!_.supportsPutFull.none) .reduce(_ || _) val anySupportPutPartial = clients.map(!_.supportsPutPartial.none).reduce(_ || _) - val anySupportHint = clients.map( _.supportsHint) .reduce(_ || _) + val anySupportHint = clients.map(!_.supportsHint.none) .reduce(_ || _) // These return Option[TLClientParameters] for your convenience def find(id: Int) = clients.find(_.sourceId.contains(id)) @@ -278,11 +274,7 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { val supportsGet = safety_helper(_.supportsGet) _ val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ - def supportsHint(id: UInt) = { - if (allSupportHint) Bool(true) else { - Mux1H(find(id), clients.map(c => Bool(c.supportsHint))) - } - } + val supportsHint = safety_helper(_.supportsHint) _ } case class TLBundleParameters( From 94761f714d627538774f9f40e51896b5b264a82c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 17:26:40 -0700 Subject: [PATCH 17/24] tilelink2 HintHandler: fill in correct sink in responses --- src/main/scala/uncore/tilelink2/Edges.scala | 3 +-- src/main/scala/uncore/tilelink2/HintHandler.scala | 5 +++-- src/main/scala/uncore/tilelink2/Parameters.scala | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 7b37c7cb..ceab2ca5 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -615,8 +615,7 @@ class TLEdgeIn( d } - // !!! buggy! deduce sink from address - def HintAck(a: TLBundleA, sink: UInt = UInt(0)): TLBundleD = HintAck(address(a), sink, a.source, a.size) + def HintAck(a: TLBundleA, fromSink: UInt): TLBundleD = HintAck(address(a), fromSink, a.source, a.size) def HintAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt) = { val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.HintAck diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index 277297d5..d44fa5f9 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -28,13 +28,14 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f require (!supportClients || bce) if (supportManagers) { - val handleA = if (passthrough) !edgeOut.manager.supportsHint(edgeIn.address(in.a.bits), edgeIn.size(in.a.bits)) else Bool(true) + val address = edgeIn.address(in.a.bits) + val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true) val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint // Prioritize existing D traffic over HintAck in.d.valid := out.d.valid || (bypassD && in.a.valid) out.d.ready := in.d.ready - in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits)) + in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address))) in.a.ready := Mux(bypassD, in.d.ready && !out.d.valid, out.a.ready) out.a.valid := in.a.valid && !bypassD diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 9648a3b5..fb36c41d 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -177,13 +177,14 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes // Synthesizable lookup methods def find(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _))) def findById(id: UInt) = Vec(managers.map(_.sinkId.contains(id))) + def findId(address: UInt) = Mux1H(find(address), managers.map(m => UInt(m.sinkId.start))) // !!! need a cheaper version of find, where we assume a valid address match exists // Does this Port manage this ID/address? def contains(address: UInt) = find(address).reduce(_ || _) def containsById(id: UInt) = findById(id).reduce(_ || _) - + private def safety_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _) if (allSame) member(managers(0)).containsLg(lgSize) else { @@ -255,11 +256,11 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { // These return Option[TLClientParameters] for your convenience def find(id: Int) = clients.find(_.sourceId.contains(id)) - + // Synthesizable lookup methods def find(id: UInt) = Vec(clients.map(_.sourceId.contains(id))) def contains(id: UInt) = find(id).reduce(_ || _) - + private def safety_helper(member: TLClientParameters => TransferSizes)(id: UInt, lgSize: UInt) = { val allSame = clients.map(member(_) == member(clients(0))).reduce(_ && _) if (allSame) member(clients(0)).containsLg(lgSize) else { From 42955a0490f4a127c1d041ac34a22807c1ac4164 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 17:31:16 -0700 Subject: [PATCH 18/24] tilelink2: HintHandler optimize to nothing if unneeded --- src/main/scala/uncore/tilelink2/HintHandler.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index d44fa5f9..6b48e758 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -27,7 +27,11 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f val bce = edgeOut.manager.anySupportAcquire && edgeIn.client.anySupportProbe require (!supportClients || bce) - if (supportManagers) { + // Does it even make sense to add the HintHandler? + val smartClients = edgeIn.client.clients.map(_.supportsHint.max == edgeIn.client.maxTransfer).reduce(_&&_) + val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_) + + if (supportManagers && !smartManagers) { val address = edgeIn.address(in.a.bits) val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true) val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint @@ -50,7 +54,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f in.d.bits := out.d.bits } - if (supportClients) { + if (supportClients && !smartClients) { val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true) val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint From 9874bc553a10a1cb02c2dcd54e18c6b8f76e5b04 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 17:31:59 -0700 Subject: [PATCH 19/24] tilelink2: Fragmenter supports Hints --- src/main/scala/uncore/tilelink2/Fragmenter.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 7495a8a3..32fd539b 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -34,7 +34,8 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten supportsLogical = expandTransfer(m.supportsLogical), supportsGet = expandTransfer(m.supportsGet), supportsPutFull = expandTransfer(m.supportsPutFull), - supportsPutPartial = expandTransfer(m.supportsPutPartial)) + supportsPutPartial = expandTransfer(m.supportsPutPartial), + supportsHint = expandTransfer(m.supportsHint)) def mapClient(c: TLClientParameters) = c.copy( sourceId = IdRange(c.sourceId.start << fragmentBits, c.sourceId.end << fragmentBits), // since we break Acquires, none of these work either: From 273d3a73f2c5be4601413601ca70bc93b2bc4a05 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 18:39:50 -0700 Subject: [PATCH 20/24] tilelink2: Unit Test passes! --- src/main/scala/junctions/unittests/UnitTest.scala | 2 +- src/main/scala/uncore/tilelink2/Fuzzer.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/junctions/unittests/UnitTest.scala b/src/main/scala/junctions/unittests/UnitTest.scala index b40be2af..723ac164 100644 --- a/src/main/scala/junctions/unittests/UnitTest.scala +++ b/src/main/scala/junctions/unittests/UnitTest.scala @@ -39,7 +39,7 @@ class UnitTestSuite(implicit p: Parameters) extends Module { state := Mux(test_idx === UInt(tests.size - 1), s_done, s_start) } - val timer = Module(new Timer(1000, tests.size)) + val timer = Module(new Timer(50000, tests.size)) timer.io.start.valid := Bool(false) timer.io.stop.valid := Bool(false) diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index 8cda783e..aaaef42c 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -81,7 +81,7 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule // Progress through operations val num_reqs = Reg(init = UInt(nOperations-1, log2Up(nOperations))) val num_resps = Reg(init = UInt(nOperations-1, log2Up(nOperations))) - io.finished := num_resps =/= UInt(0) + io.finished := num_resps === UInt(0) // Progress within each operation val a = out.a.bits From 70054226519cdec81f228608870913f82a7a0fb0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 19:06:35 -0700 Subject: [PATCH 21/24] tilelink2 HintHandler: don't HintAck in the middle of a multibeat op --- src/main/scala/uncore/tilelink2/Fuzzer.scala | 4 ++-- .../scala/uncore/tilelink2/HintHandler.scala | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index aaaef42c..7c9b2625 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -184,8 +184,8 @@ class TLFuzzRAM extends LazyModule val fuzz = LazyModule(new TLFuzzer(1000)) model.node := fuzz.node - xbar.node := TLWidthWidget(model.node, 16) - ram.node := TLHintHandler(TLFragmenter(TLBuffer(xbar.node), 4, 256)) + xbar.node := TLWidthWidget(TLHintHandler(model.node), 16) + ram.node := TLFragmenter(TLBuffer(xbar.node), 4, 256) lazy val module = new LazyModuleImp(this) with HasUnitTestIO { io.finished := fuzz.module.io.finished diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index 6b48e758..3d57f03c 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -36,12 +36,17 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true) val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint - // Prioritize existing D traffic over HintAck - in.d.valid := out.d.valid || (bypassD && in.a.valid) + // Prioritize existing D traffic over HintAck (and finish multibeat xfers) + val beats1 = edgeOut.numBeats1(out.d.bits) + val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes))) + val first = counter === UInt(0) + when (out.d.fire()) { counter := Mux(first, beats1, counter - UInt(1)) } + + in.d.valid := out.d.valid || (bypassD && in.a.valid && first) out.d.ready := in.d.ready in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address))) - in.a.ready := Mux(bypassD, in.d.ready && !out.d.valid, out.a.ready) + in.a.ready := Mux(bypassD, in.d.ready && first && !out.d.valid, out.a.ready) out.a.valid := in.a.valid && !bypassD out.a.bits := in.a.bits } else { @@ -58,12 +63,17 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true) val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint - // Prioritize existing C traffic over HintAck - out.c.valid := in.c.valid || (bypassC && in.b.valid) + // Prioritize existing C traffic over HintAck (and finish multibeat xfers) + val beats1 = edgeIn.numBeats1(in.c.bits) + val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes))) + val first = counter === UInt(0) + when (in.c.fire()) { counter := Mux(first, beats1, counter - UInt(1)) } + + out.c.valid := in.c.valid || (bypassC && in.b.valid && first) in.c.ready := out.c.ready out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits)) - out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) + out.b.ready := Mux(bypassC, out.c.ready && first && !in.c.valid, in.b.ready) in.b.valid := out.b.valid && !bypassC in.b.bits := out.b.bits } else if (bce) { From 606f19a17f4e760387c368b1492fa8027486b098 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 12 Sep 2016 21:41:36 -0700 Subject: [PATCH 22/24] tilelink2: RegisterRouter Unit Test --- .../scala/junctions/unittests/UnitTest.scala | 2 +- src/main/scala/uncore/tilelink2/Fuzzer.scala | 6 +- .../scala/uncore/tilelink2/RAMModel.scala | 2 +- .../uncore/tilelink2/RegisterRouterTest.scala | 102 ++++++++++++++++-- 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/src/main/scala/junctions/unittests/UnitTest.scala b/src/main/scala/junctions/unittests/UnitTest.scala index 723ac164..77dd146b 100644 --- a/src/main/scala/junctions/unittests/UnitTest.scala +++ b/src/main/scala/junctions/unittests/UnitTest.scala @@ -39,7 +39,7 @@ class UnitTestSuite(implicit p: Parameters) extends Module { state := Mux(test_idx === UInt(tests.size - 1), s_done, s_start) } - val timer = Module(new Timer(50000, tests.size)) + val timer = Module(new Timer(100000, tests.size)) timer.io.start.valid := Bool(false) timer.io.stop.valid := Bool(false) diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index 7c9b2625..42469fb4 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -179,13 +179,15 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule class TLFuzzRAM extends LazyModule { val model = LazyModule(new TLRAMModel) - val ram = LazyModule(new TLRAM(AddressSet(0, 0xfff))) + val ram = LazyModule(new TLRAM(AddressSet(0, 0x3ff))) + val gpio = LazyModule(new RRTest1(0x400)) val xbar = LazyModule(new TLXbar) - val fuzz = LazyModule(new TLFuzzer(1000)) + val fuzz = LazyModule(new TLFuzzer(5000)) model.node := fuzz.node xbar.node := TLWidthWidget(TLHintHandler(model.node), 16) ram.node := TLFragmenter(TLBuffer(xbar.node), 4, 256) + gpio.node := TLFragmenter(TLBuffer(xbar.node), 4, 32) lazy val module = new LazyModuleImp(this) with HasUnitTestIO { io.finished := fuzz.module.io.finished diff --git a/src/main/scala/uncore/tilelink2/RAMModel.scala b/src/main/scala/uncore/tilelink2/RAMModel.scala index 45172b3a..ce3ddb70 100644 --- a/src/main/scala/uncore/tilelink2/RAMModel.scala +++ b/src/main/scala/uncore/tilelink2/RAMModel.scala @@ -223,7 +223,7 @@ class TLRAMModel extends LazyModule when (!shadow.valid) { printf("G 0x%x := undefined\n", d_addr_hi << shift | UInt(i)) } .otherwise { - printf("G 0x%x := 0x%x\n", d_addr_hi << shift | UInt(i), shadow.value) + printf("G 0x%x := 0x%x\n", d_addr_hi << shift | UInt(i), got) assert (shadow.value === got) } } diff --git a/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala b/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala index a93112f5..65dde1d3 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouterTest.scala @@ -9,7 +9,7 @@ object LFSR16Seed def apply(seed: Int): UInt = { val width = 16 - val lfsr = Reg(init=UInt(seed, width)) + val lfsr = Reg(init=UInt((seed*0x7231) % 65536, width)) lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) lfsr } @@ -39,12 +39,11 @@ class RRTestCombinational(val bits: Int, rvalid: Bool => Bool, wready: Bool => B object RRTestCombinational { - private var seed = 0 + private var seed = 42 def always: Bool => Bool = _ => Bool(true) def random: Bool => Bool = { seed = seed + 1 - val lfsr = LFSR16Seed(seed) - _ => lfsr(0) + _ => LFSR16Seed(seed)(0) } def delay(x: Int): Bool => Bool = { fire => val reg = RegInit(UInt(0, width = log2Ceil(x+1))) @@ -96,32 +95,40 @@ class RRTestRequest(val bits: Int, object RRTestRequest { - private var seed = 0 + private var seed = 1231 def pipe(x: Int): (Bool, Bool, UInt) => (Bool, Bool, UInt) = { (ivalid, oready, idata) => val full = RegInit(Vec.fill(x)(Bool(false))) - val ready = Wire(Vec.fill(x)(Bool())) - val data = Reg(Vec.fill(x)(UInt(width = idata.getWidth))) + val ready = Wire(Vec(x, Bool())) + val data = Reg(Vec(x, UInt(width = idata.getWidth))) // Construct a classic bubble-filling pipeline - ready(x) := oready || !full(x) + ready(x-1) := oready || !full(x-1) when (ready(0)) { data(0) := idata } + when (ready(0)) { full(0) := ivalid } ((ready.init zip ready.tail) zip full.init) foreach { case ((self, next), full) => self := next || !full } ((data.init zip data.tail) zip ready.tail) foreach { case ((prev, self), ready) => when (ready) { self := prev } } - (ready(0), full(x), Mux(full(x) && oready, data(x), UInt(0))) + ((full.init zip full.tail) zip ready.tail) foreach { case ((prev, self), ready) => + when (ready) { self := prev } + } + (ready(0), full(x-1), data(x-1)) } def busy: (Bool, Bool, UInt) => (Bool, Bool, UInt) = { seed = seed + 1 - val lfsr = LFSR16Seed(seed) (ivalid, oready, idata) => { + val lfsr = LFSR16Seed(seed) val busy = RegInit(Bool(false)) + val data = Reg(UInt(width = idata.getWidth)) val progress = lfsr(0) when (progress) { busy := Mux(busy, !oready, ivalid) } - (progress && !busy, progress && busy, idata) + val iready = progress && !busy + val ovalid = progress && busy + when (ivalid && iready) { data := idata } + (iready, ovalid, data) } } def request(bits: Int, @@ -140,3 +147,76 @@ object RRTestRequest (request.io.wiready, request.io.wovalid) }) } } + +object RRTest0Map +{ + import RRTestCombinational._ + + def aa(bits: Int) = combo(bits, always, always) + def ar(bits: Int) = combo(bits, always, random) + def ad(bits: Int) = combo(bits, always, delay(11)) + def ae(bits: Int) = combo(bits, always, delay(5)) + def ra(bits: Int) = combo(bits, random, always) + def rr(bits: Int) = combo(bits, random, random) + def rd(bits: Int) = combo(bits, random, delay(11)) + def re(bits: Int) = combo(bits, random, delay(5)) + def da(bits: Int) = combo(bits, delay(5), always) + def dr(bits: Int) = combo(bits, delay(5), random) + def dd(bits: Int) = combo(bits, delay(5), delay(5)) + def de(bits: Int) = combo(bits, delay(5), delay(11)) + def ea(bits: Int) = combo(bits, delay(11), always) + def er(bits: Int) = combo(bits, delay(11), random) + def ed(bits: Int) = combo(bits, delay(11), delay(5)) + def ee(bits: Int) = combo(bits, delay(11), delay(11)) + + // All fields must respect byte alignment, or else it won't behave like an SRAM + val map = Seq( + 0 -> Seq(aa(8), ar(8), ad(8), ae(8)), + 1 -> Seq(ra(8), rr(8), rd(8), re(8)), + 2 -> Seq(da(8), dr(8), dd(8), de(8)), + 3 -> Seq(ea(8), er(8), ed(8), ee(8)), + 4 -> Seq(aa(3), ar(5), ad(1), ae(7), ra(2), rr(6), rd(4), re(4)), + 5 -> Seq(da(3), dr(5), dd(1), de(7), ea(2), er(6), ed(4), ee(4)), + 6 -> Seq(aa(8), rr(8), dd(8), ee(8)), + 7 -> Seq(ar(8), rd(8), de(8), ea(8))) +} + +object RRTest1Map +{ + import RRTestRequest._ + + def pp(bits: Int) = request(bits, pipe(3), pipe(3)) + def pb(bits: Int) = request(bits, pipe(3), busy) + def bp(bits: Int) = request(bits, busy, pipe(3)) + def bb(bits: Int) = request(bits, busy, busy) + + val map = RRTest0Map.map.take(6) ++ Seq( + 6 -> Seq(pp(8), pb(8), bp(8), bb(8)), + 7 -> Seq(pp(3), pb(5), bp(1), bb(7), pb(5), bp(3), pp(4), bb(4))) +} + +trait RRTest0Bundle +{ +} + +trait RRTest0Module extends HasRegMap +{ + regmap(RRTest0Map.map:_*) +} + +class RRTest0(address: BigInt) extends TLRegisterRouter(address, 0, 32, Some(0), 4)( + new TLRegBundle((), _) with RRTest0Bundle)( + new TLRegModule((), _, _) with RRTest0Module) + +trait RRTest1Bundle +{ +} + +trait RRTest1Module extends HasRegMap +{ + regmap(RRTest1Map.map:_*) +} + +class RRTest1(address: BigInt) extends TLRegisterRouter(address, 0, 32, Some(6), 4)( + new TLRegBundle((), _) with RRTest1Bundle)( + new TLRegModule((), _, _) with RRTest1Module) From e318c29d48583ddcf0600ea1ec171ab4a93eb72b Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Tue, 13 Sep 2016 12:25:57 -0700 Subject: [PATCH 23/24] [tilelink2] Fuzzer: Allow noise-making to be parameterized. Better comments. --- src/main/scala/uncore/tilelink2/Fuzzer.scala | 56 +++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index 42469fb4..b2a734f8 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -50,15 +50,39 @@ object LFSR64 } } -object NoiseMaker +trait HasNoiseMakerIO { - def apply(wide: Int, increment: Bool = Bool(true)): UInt = { - val lfsrs = Seq.fill((wide+63)/64) { LFSR64(increment) } - Cat(lfsrs)(wide-1,0) + val io = new Bundle { + val inc = Bool(INPUT) + val random = UInt(OUTPUT) } } -class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule +class LFSRNoiseMaker(wide: Int) extends Module with HasNoiseMakerIO +{ + val lfsrs = Seq.fill((wide+63)/64) { LFSR64(io.inc) } + io.random := Cat(lfsrs)(wide-1,0) +} + +object LFSRNoiseMaker { + def apply(wide: Int, increment: Bool = Bool(true)): UInt = { + val nm = Module(new LFSRNoiseMaker(wide)) + nm.io.inc := increment + nm.io.random + } +} + +/** TLFuzzer drives test traffic over TL2 links. It generates a sequence of randomized + * requests, and issues legal ones into the DUT. TODO: Currently the fuzzer only generates + * memory operations, not permissions transfers. + * @param nOperations is the total number of operations that the fuzzer must complete for the test to pass + * @param inFlight is the number of operations that can be in-flight to the DUT concurrently + * @param noiseMaker is a function that supplies a random UInt of a given width every time inc is true + */ +class TLFuzzer( + nOperations: Int, + inFlight: Int = 32, + noiseMaker: (Int, Bool) => UInt = LFSRNoiseMaker.apply _) extends LazyModule { val node = TLClientNode(TLClientParameters(sourceId = IdRange(0,inFlight))) @@ -70,6 +94,8 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule val out = io.out(0) val edge = node.edgesOut(0) + + // Extract useful parameters from the TL edge val endAddress = edge.manager.maxAddress + 1 val maxTransfer = edge.manager.maxTransfer val beatBytes = edge.manager.beatBytes @@ -111,14 +137,15 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule // Increment random number generation for the following subfields val inc = Wire(Bool()) val inc_beat = Wire(Bool()) - val arth_op = NoiseMaker(3, inc) - val log_op = NoiseMaker(2, inc) - val amo_size = UInt(2) + NoiseMaker(1, inc) // word or dword - val size = NoiseMaker(sizeBits, inc) - val addr = NoiseMaker(addressBits, inc) & ~UIntToOH1(size, addressBits) - val mask = NoiseMaker(beatBytes, inc_beat) & edge.mask(addr, size) - val data = NoiseMaker(dataBits, inc_beat) + val arth_op = noiseMaker(3, inc) + val log_op = noiseMaker(2, inc) + val amo_size = UInt(2) + noiseMaker(1, inc) // word or dword + val size = noiseMaker(sizeBits, inc) + val addr = noiseMaker(addressBits, inc) & ~UIntToOH1(size, addressBits) + val mask = noiseMaker(beatBytes, inc_beat) & edge.mask(addr, size) + val data = noiseMaker(dataBits, inc_beat) + // Actually generate specific TL messages when it is legal to do so val (glegal, gbits) = edge.Get(src, addr, size) val (pflegal, pfbits) = if(edge.manager.anySupportPutFull) { edge.Put(src, addr, size, data) @@ -136,7 +163,8 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule edge.Hint(src, addr, size, UInt(0)) } else { (glegal, gbits) } - val a_type_sel = NoiseMaker(3, inc) + // Pick a specific message to try to send + val a_type_sel = noiseMaker(3, inc) val legal = MuxLookup(a_type_sel, glegal, Seq( UInt("b000") -> glegal, @@ -154,6 +182,7 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule UInt("b100") -> lbits, UInt("b101") -> hbits)) + // Wire both the used and un-used channel signals out.a.valid := legal && alloc.valid && num_reqs =/= UInt(0) out.a.bits := bits out.b.ready := Bool(true) @@ -161,6 +190,7 @@ class TLFuzzer(nOperations: Int, inFlight: Int = 32) extends LazyModule out.d.ready := Bool(true) out.e.valid := Bool(false) + // Increment the various progress-tracking states inc := !legal || req_done inc_beat := !legal || out.a.fire() From 632b5896b9fadab342222fe8ae480ae72ab6e569 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Tue, 13 Sep 2016 13:29:48 -0700 Subject: [PATCH 24/24] Delete TestGraphs.scala Re-do later using Fuzzer --- .../scala/uncore/tilelink2/TestGraphs.scala | 92 ------------------- 1 file changed, 92 deletions(-) delete mode 100644 src/main/scala/uncore/tilelink2/TestGraphs.scala diff --git a/src/main/scala/uncore/tilelink2/TestGraphs.scala b/src/main/scala/uncore/tilelink2/TestGraphs.scala deleted file mode 100644 index 169a82d1..00000000 --- a/src/main/scala/uncore/tilelink2/TestGraphs.scala +++ /dev/null @@ -1,92 +0,0 @@ -// See LICENSE for license details. -package uncore.tilelink2 - -import Chisel._ -import chisel3.util.LFSR16 -import junctions.unittests._ - -class TLClient extends LazyModule -{ - val node = TLClientNode(TLClientParameters()) - - lazy val module = new LazyModuleImp(this) { - val io = new Bundle { - val out = node.bundleOut - val finished = Bool() - } - - require (node.edgesOut(0).manager.beatBytes == 16) - - val addr = RegInit(UInt(0, width = 13)) - val size = RegInit(UInt(0, width = 4)) - val put = RegInit(Bool(false)) - val width = 12 - val count = RegInit(UInt(0, width = width)) - val limit = ~(SInt(-1, width=width).asUInt << size)(width-1, 0) >> 4 - - val out = io.out(0) - val edge = node.edgesOut(0) - val data = Cat(Seq.tabulate(16) { i => UInt(i) | (count(3,0) + UInt(1)) << 4 } .reverse) - - val (legalg, gbits) = edge.Get(UInt(0), addr, size) - val (legalp, pbits) = edge.Put(UInt(0), addr, size, data) - val legal = Mux(put, legalp, legalg) - val bits = Mux(put, pbits, gbits) - - out.a.valid := legal - out.a.bits := bits - out.b.ready := Bool(true) - out.c.valid := Bool(false) - out.d.ready := Bool(true) - out.e.valid := Bool(false) - io.finished := Bool(true)//count === limit - - when (out.a.fire()) { count := count + UInt(1) } - when (!legal || (out.a.fire() && Mux(put, count === limit, Bool(true)))) { - count := UInt(0) - size := size + UInt(1) - put := LFSR16()(0) - addr := addr + UInt(0x100) - when (size === UInt(8)) { size := UInt(0) } - } - } -} - -class Bar extends LazyModule -{ - val node = TLOutputNode() - - val client = LazyModule(new TLClient) - val xbar = LazyModule(new TLXbar) - - connect(client.node -> xbar.node) - connect(xbar.node -> node) - - lazy val module = new LazyModuleImp(this) { - val io = new Bundle { - val out = node.bundleOut - val finished = Bool() - } - io.finished := client.module.io.finished - } -} - -class TLXbarGPIORAM extends LazyModule -{ - val ram = LazyModule(new TLRAM(AddressSet(0, 0xfff))) - val xbar = LazyModule(new TLXbar) - val bar = LazyModule(new Bar) - - connect(TLWidthWidget(TLHintHandler(bar.node), 16) -> xbar.node) - connect(TLFragmenter(TLBuffer(xbar.node), 4, 256) -> ram.node) - - lazy val module = new LazyModuleImp(this) with HasUnitTestIO { - io.finished := bar.module.io.finished - } -} - -class TLXbarGPIORAMTest extends UnitTest { - val dut = LazyModule(new TLXbarGPIORAM).module - io.finished := dut.io.finished -} -