diff --git a/axi4/.gitignore b/axi4/.gitignore index 7a2ef20..6dd29ed 100644 --- a/axi4/.gitignore +++ b/axi4/.gitignore @@ -1,5 +1,6 @@ # Ignore metals-related temp files .bloop/ +.ionide/ .metals/ .vscode/ project/.bloop/ diff --git a/axi4/src/main/scala/axi4/Bundles.scala b/axi4/src/main/scala/axi4/Bundles.scala new file mode 100644 index 0000000..0dcec64 --- /dev/null +++ b/axi4/src/main/scala/axi4/Bundles.scala @@ -0,0 +1,151 @@ +/** + * Author: Hans Jakob Damsgaard, hansjakobdamsgaard@gmail.com + * + * Purpose: Implementation of a testing framework for AXI4-compliant devices. + * + * Content: Bundle definitions for AXI4. +*/ + +package axi4 + +import chisel3._ +import chisel3.util.isPow2 + +/** AXI4 write address + * + * @param addrW the width of the AWADDR signal in bits + * @param idW the width of the AWID signal in bits + * @param userW the width of the AWUSER signal in bits + */ +class WA(val addrW: Int, val idW: Int, val userW: Int) extends Bundle { + require(addrW > 0, "the address width must be a positive integer") + require(idW >= 0, "the id width must be a non-negative integer") + require(userW >= 0, "the user with must be a non-negative integer") + val id = UInt(idW.W) + val addr = UInt(addrW.W) + val len = UInt(8.W) + val size = UInt(3.W) + val burst = UInt(2.W) + val lock = Bool() + val cache = UInt(4.W) + val prot = UInt(3.W) + val qos = UInt(4.W) + val region = UInt(4.W) + val user = UInt(userW.W) +} +object WA { + /** Alternative constructor + * + * @param addrW the width of the AWADDR signal in bits + * @param idW the width of the AWID signal in bits, defaults to 0 + * @param userW the width of the AWUSER signal in bits, defaults to 0 + * @return + */ + def apply(addrW: Int, idW: Int = 0, userW: Int = 0) = new WA(addrW, idW, userW) +} + +/** AXI4 write data + * + * @param dataW the width of the WDATA signal in bits + * @param userW the width of the WUSER signal in bits + */ +class WD(val dataW: Int, val userW: Int) extends Bundle { + require(dataW > 0, "the data width must be a positive integer") + require(isPow2(dataW / 8), "the data width must be a power of 2 multiple of bytes") + require(userW >= 0, "the user with must be a non-negative integer") + val data = UInt(dataW.W) + val strb = UInt((dataW/8).W) + val last = Bool() + val user = UInt(userW.W) +} +object WD { + /** Alternative constructor + * + * @param dataW the width of the WDATA signal in bits + * @param userW the width of the WUSER signal in bits, defaults to 0 + * @return an unitialized WD object + */ + def apply(dataW: Int, userW: Int = 0) = new WD(dataW, userW) +} + +/** AXI4 write response + * + * @param idW the width of the BID signal in bits + * @param userW the width of the BUSER signal in bits + */ +class WR(val idW: Int, val userW: Int) extends Bundle { + require(idW >= 0, "the id width must be a non-negative integer") + require(userW >= 0, "the user with must be a non-negative integer") + val id = UInt(idW.W) + val resp = UInt(2.W) + val user = UInt(userW.W) +} +object WR { + /** Alternative constructor + * + * @param idW the width of the BID signal in bits, defaults to 0 + * @param userW the width of the BUSER signal in bits, defaults to 0 + * @return an unitialized WR object + */ + def apply(idW: Int = 0, userW: Int = 0) = new WR(idW, userW) +} + +/** AXI4 read address + * + * @param addrW the width of the ARADDR signal in bits + * @param idW the width of the ARID signal in bits + * @param userW the width of the ARUSER signal in bits + */ +class RA(val addrW: Int, val idW: Int, val userW: Int) extends Bundle { + require(addrW > 0, "the address width must be a positive integer") + require(idW >= 0, "the id width must be a non-negative integer") + require(userW >= 0, "the user with must be a non-negative integer") + val id = UInt(idW.W) + val addr = UInt(addrW.W) + val len = UInt(8.W) + val size = UInt(3.W) + val burst = UInt(2.W) + val lock = Bool() + val cache = UInt(4.W) + val prot = UInt(3.W) + val qos = UInt(4.W) + val region = UInt(4.W) + val user = UInt(userW.W) +} +object RA { + /** Alternative constructor + * + * @param addrW the width of the ARADDR signal in bits + * @param idW the width of the ARID signal in bits, defaults to 0 + * @param userW the width of the ARUSER signal in bits, defaults to 0 + * @return an unitialized RA object + */ + def apply(addrW: Int, idW: Int = 0, userW: Int = 0) = new RA(addrW, idW, userW) +} + +/** AXI4 read data + * + * @param dataW the width of the RDATA signal in bits + * @param idW the width of the RID signal in bits + * @param userW the width of the RUSER signal in bits + */ +class RD(val dataW: Int, val idW: Int, val userW: Int) extends Bundle { + require(isPow2(dataW / 8), "the data width must be a power of 2 multiple of bytes") + require(idW >= 0, "the id width must be a non-negative integer") + require(userW >= 0, "the user with must be a non-negative integer") + val id = UInt(idW.W) + val data = UInt(dataW.W) + val resp = UInt(2.W) + val last = Bool() + val user = UInt(userW.W) +} +object RD { + /** Alternative constructor + * + * @param dataW the width of the RDATA signal in bits + * @param idW the width of the RID signal in bits, defaults to 0 + * @param userW the width of the RUSER signal in bits, defaults to 0 + * @return an uninitialized RD object + */ + def apply(dataW: Int, idW: Int = 0, userW: Int = 0) = new RD(dataW, idW, userW) +} diff --git a/axi4/src/main/scala/axi4/Defs.scala b/axi4/src/main/scala/axi4/Defs.scala deleted file mode 100644 index 49df6ec..0000000 --- a/axi4/src/main/scala/axi4/Defs.scala +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Author: Hans Jakob Damsgaard, hansjakobdamsgaard@gmail.com - * - * Purpose: Implementation of a testing framework for AXI4-compliant devices. - * - * Content: Interface definitions for AXI4. -*/ - -package axi4 - -import chisel3._ -import chisel3.util._ - -/** AXI4 write address interface - * - * @param addrW the width of the AWADDR signal in bits - * @param idW the width of the AWID signal in bits, defaults to 0 - * @param userW the width of the AWUSER signal in bits, defaults to 0 - */ -class WA(val addrW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { - require(addrW > 0, "the address width must be a positive integer") - require(idW >= 0, "the id width must be a non-negative integer") - require(userW >= 0, "the user with must be a non-negative integer") - val id = Output(UInt(idW.W)) - val addr = Output(UInt(addrW.W)) - val len = Output(UInt(8.W)) - val size = Output(UInt(3.W)) - val burst = Output(UInt(2.W)) - val lock = Output(Bool()) - val cache = Output(UInt(4.W)) - val prot = Output(UInt(3.W)) - val qos = Output(UInt(4.W)) - val region = Output(UInt(4.W)) - val user = Output(UInt(userW.W)) -} - -/** AXI4 write data interface - * - * @param dataW the width of the WDATA signal in bits - * @param userW the width of the WUSER signal in bits, defaults to 0 - */ -class WD(val dataW: Int, val userW: Int = 0) extends Bundle { - require(dataW > 0, "the data width must be a positive integer") - require(isPow2(dataW / 8), "the data width must be a power of 2 multiple of bytes") - require(userW >= 0, "the user with must be a non-negative integer") - val data = Output(UInt(dataW.W)) - val strb = Output(UInt((dataW/8).W)) - val last = Output(Bool()) - val user = Output(UInt(userW.W)) -} - -/** AXI4 write response interface - * - * @param idW the width of the BID signal in bits, defaults to 0 - * @param userW the width of the BUSER signal in bits, defaults to 0 - */ -class WR(val idW: Int = 0, val userW: Int = 0) extends Bundle { - require(idW >= 0, "the id width must be a non-negative integer") - require(userW >= 0, "the user with must be a non-negative integer") - val id = Input(UInt(idW.W)) - val resp = Input(UInt(2.W)) - val user = Input(UInt(userW.W)) -} - -/** AXI4 read address interface - * - * @param addrW the width of the ARADDR signal in bits - * @param idW the width of the ARID signal in bits, defaults to 0 - * @param userW the width of the ARUSER signal in bits, defaults to 0 - */ -class RA(val addrW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { - require(addrW > 0, "the address width must be a positive integer") - require(idW >= 0, "the id width must be a non-negative integer") - require(userW >= 0, "the user with must be a non-negative integer") - val id = Output(UInt(idW.W)) - val addr = Output(UInt(addrW.W)) - val len = Output(UInt(8.W)) - val size = Output(UInt(3.W)) - val burst = Output(UInt(2.W)) - val lock = Output(Bool()) - val cache = Output(UInt(4.W)) - val prot = Output(UInt(3.W)) - val qos = Output(UInt(4.W)) - val region = Output(UInt(4.W)) - val user = Output(UInt(userW.W)) -} - -/** AXI4 read data interface - * - * @param dataW the width of the RDATA signal in bits - * @param idW the width of the RID signal in bits, defaults to 0 - * @param userW the width of the RUSER signal in bits, defaults to 0 - */ -class RD(val dataW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { - require(isPow2(dataW / 8), "the data width must be a power of 2 multiple of bytes") - require(idW >= 0, "the id width must be a non-negative integer") - require(userW >= 0, "the user with must be a non-negative integer") - val id = Input(UInt(idW.W)) - val data = Input(UInt(dataW.W)) - val resp = Input(UInt(2.W)) - val last = Input(Bool()) - val user = Input(UInt(userW.W)) -} - -/** AXI4 master interface - * - * @param addrW the width of the address signals in bits - * @param dataW the width of the data read/write signals in bits - * @param idW the width of the ID signals in bits, defaults to 0 - * @param userW the width of the user signals in bits, defaults to 0 - */ -class MasterInterface(val addrW: Int, val dataW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { - /** Fields implementing each of the AXI channels - * - * [[aw]] is the write address channel - * [[dw]] is the write data channel - * [[wr]] is the write response channel - * [[ar]] is the read address channel - * [[dr]] is the read data channel - */ - val aw = Decoupled(new WA(addrW, idW, userW)) - val dw = Decoupled(new WD(dataW, userW)) - val wr = Flipped(Decoupled(Flipped(new WR(idW, userW)))) - val ar = Decoupled(new RA(addrW, idW, userW)) - val dr = Flipped(Decoupled(Flipped(new RD(dataW, idW, userW)))) -} - -/** AXI4 slave interface - * - * @param addrW the width of the address signals in bits - * @param dataW the width of the data read/write signals in bits - * @param idW the width of the ID signals in bits, defaults to 0 - * @param userW the width of the user signals in bits, defaults to 0 - */ -class SlaveInterface(val addrW: Int, val dataW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { - /** Fields implementing each of the AXI channels - * - * [[aw]] is the write address channel - * [[dw]] is the write data channel - * [[wr]] is the write response channel - * [[ar]] is the read address channel - * [[dr]] is the read data channel - */ - val aw = Flipped(Decoupled(new WA(addrW, idW, userW))) - val dw = Flipped(Decoupled(new WD(dataW, userW))) - val wr = Flipped(Flipped(Decoupled(Flipped(new WR(idW, userW))))) - val ar = Flipped(Decoupled(new RA(addrW, idW, userW))) - val dr = Flipped(Flipped(Decoupled(Flipped(new RD(dataW, idW, userW))))) -} diff --git a/axi4/src/main/scala/axi4/FunctionalMaster.scala b/axi4/src/main/scala/axi4/FunctionalMaster.scala index 4712e06..e61a22e 100644 --- a/axi4/src/main/scala/axi4/FunctionalMaster.scala +++ b/axi4/src/main/scala/axi4/FunctionalMaster.scala @@ -54,7 +54,7 @@ class FunctionalMaster[T <: Slave](dut: T) { /** Default values on all signals */ // Address write - aw.bits.id.poke(0.U) + if (aw.bits.idW > 0) aw.bits.id.poke(0.U) aw.bits.addr.poke(0.U) aw.bits.len.poke(0.U) aw.bits.size.poke(0.U) @@ -64,19 +64,21 @@ class FunctionalMaster[T <: Slave](dut: T) { aw.bits.prot.poke(ProtectionEncodings.DataNsecUpriv) aw.bits.qos.poke(0.U) aw.bits.region.poke(0.U) + if (aw.bits.userW > 0) aw.bits.user.poke(0.U) aw.valid.poke(false.B) // Data write dw.bits.data.poke(0.U) dw.bits.strb.poke(0.U) dw.bits.last.poke(false.B) + if (dw.bits.userW > 0) dw.bits.user.poke(0.U) dw.valid.poke(false.B) // Write response wr.ready.poke(false.B) // Address read - ar.bits.id.poke(0.U) + if (ar.bits.idW > 0) ar.bits.id.poke(0.U) ar.bits.addr.poke(0.U) ar.bits.len.poke(0.U) ar.bits.size.poke(0.U) @@ -86,6 +88,7 @@ class FunctionalMaster[T <: Slave](dut: T) { ar.bits.prot.poke(ProtectionEncodings.DataNsecUpriv) ar.bits.qos.poke(0.U) ar.bits.region.poke(0.U) + if (ar.bits.userW > 0) ar.bits.user.poke(0.U) ar.valid.poke(false.B) // Data read @@ -122,7 +125,7 @@ class FunctionalMaster[T <: Slave](dut: T) { /** Write address to slave */ aw.valid.poke(true.B) - aw.bits.id.poke(head.id.U) + if (aw.bits.idW > 0) aw.bits.id.poke(head.id.U) aw.bits.addr.poke(head.addr.U) aw.bits.len.poke(head.len.U) aw.bits.size.poke(head.size.U) @@ -132,6 +135,7 @@ class FunctionalMaster[T <: Slave](dut: T) { aw.bits.prot.poke(head.prot) aw.bits.qos.poke(head.qos) aw.bits.region.poke(head.region) + if (aw.bits.userW > 0) aw.bits.user.poke(head.user) while (!aw.ready.peek.litToBoolean) { clk.step() } @@ -163,11 +167,12 @@ class FunctionalMaster[T <: Slave](dut: T) { /** Write data to slave */ dw.valid.poke(true.B) while (!head.complete) { - val (data, strb, last) = head.next + val (data, strb, last, user) = head.next println("Write " + data.litValue + " with strobe " + strb.toString + " and last " + last.litToBoolean) dw.bits.data.poke(data) dw.bits.strb.poke(strb) dw.bits.last.poke(last) + if (dw.bits.userW > 0) dw.bits.user.poke(user) while (!dw.ready.peek.litToBoolean) { clk.step() } @@ -202,7 +207,7 @@ class FunctionalMaster[T <: Slave](dut: T) { while (!wr.valid.peek.litToBoolean) { clk.step() } - responses = responses :+ (new Response(wr.bits.resp.peek, wr.bits.id.peek.litValue)) + responses = responses :+ (new Response(wr.bits.resp.peek, if (wr.bits.idW > 0) wr.bits.id.peek.litValue else 0)) wr.ready.poke(false.B) /** Update queue */ @@ -225,7 +230,7 @@ class FunctionalMaster[T <: Slave](dut: T) { /** Write address to slave */ ar.valid.poke(true.B) - ar.bits.id.poke(head.id.U) + if (ar.bits.idW > 0) ar.bits.id.poke(head.id.U) ar.bits.addr.poke(head.addr.U) ar.bits.len.poke(head.len.U) ar.bits.size.poke(head.size.U) @@ -235,6 +240,7 @@ class FunctionalMaster[T <: Slave](dut: T) { ar.bits.prot.poke(head.prot) ar.bits.qos.poke(head.qos) ar.bits.region.poke(head.region) + if (ar.bits.userW > 0) ar.bits.user.poke(head.user) while (!ar.ready.peek.litToBoolean) { clk.step() } diff --git a/axi4/src/main/scala/axi4/Interfaces.scala b/axi4/src/main/scala/axi4/Interfaces.scala new file mode 100644 index 0000000..950c83b --- /dev/null +++ b/axi4/src/main/scala/axi4/Interfaces.scala @@ -0,0 +1,58 @@ +/** + * Author: Hans Jakob Damsgaard, hansjakobdamsgaard@gmail.com + * + * Purpose: Implementation of a testing framework for AXI4-compliant devices. + * + * Content: Interface definitions for AXI4. +*/ + +package axi4 + +import chisel3._ +import chisel3.util.Decoupled + +/** AXI4 master interface + * + * @param addrW the width of the address signals in bits + * @param dataW the width of the data read/write signals in bits + * @param idW the width of the ID signals in bits, defaults to 0 + * @param userW the width of the user signals in bits, defaults to 0 + */ +class MasterInterface(val addrW: Int, val dataW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { + /** Fields implementing each of the AXI channels + * + * [[aw]] is the write address channel + * [[dw]] is the write data channel + * [[wr]] is the write response channel + * [[ar]] is the read address channel + * [[dr]] is the read data channel + */ + val aw = Decoupled(Output(WA(addrW, idW, userW))) //Decoupled(new WA(addrW, idW, userW)) + val dw = Decoupled(Output(WD(dataW, userW))) //Decoupled(new WD(dataW, userW)) + val wr = Flipped(Decoupled(Output(WR(idW, userW)))) //Flipped(Decoupled(Flipped(new WR(idW, userW)))) + val ar = Decoupled(RA(addrW, idW, userW)) //Decoupled(new RA(addrW, idW, userW)) + val dr = Flipped(Decoupled(Output(RD(dataW, idW, userW)))) //Flipped(Decoupled(Flipped(new RD(dataW, idW, userW)))) +} + +/** AXI4 slave interface + * + * @param addrW the width of the address signals in bits + * @param dataW the width of the data read/write signals in bits + * @param idW the width of the ID signals in bits, defaults to 0 + * @param userW the width of the user signals in bits, defaults to 0 + */ +class SlaveInterface(val addrW: Int, val dataW: Int, val idW: Int = 0, val userW: Int = 0) extends Bundle { + /** Fields implementing each of the AXI channels + * + * [[aw]] is the write address channel + * [[dw]] is the write data channel + * [[wr]] is the write response channel + * [[ar]] is the read address channel + * [[dr]] is the read data channel + */ + val aw = Flipped(Decoupled(Output(WA(addrW, idW, userW)))) //Flipped(Decoupled(new WA(addrW, idW, userW))) + val dw = Flipped(Decoupled(Output(WD(dataW, userW)))) //Flipped(Decoupled(new WD(dataW, userW))) + val wr = Decoupled(Output(WR(idW, userW))) //Flipped(Flipped(Decoupled(Flipped(new WR(idW, userW))))) + val ar = Flipped(Decoupled(Output(RA(addrW, idW, userW)))) //Flipped(Decoupled(new RA(addrW, idW, userW))) + val dr = Decoupled(Output(RD(dataW, idW, userW))) //Flipped(Flipped(Decoupled(Flipped(new RD(dataW, idW, userW))))) +} diff --git a/axi4/src/main/scala/axi4/Transaction.scala b/axi4/src/main/scala/axi4/Transaction.scala index 1ef6299..dfb58a6 100644 --- a/axi4/src/main/scala/axi4/Transaction.scala +++ b/axi4/src/main/scala/axi4/Transaction.scala @@ -29,6 +29,7 @@ trait Transaction { * @param prot optional protection type, defaults to non-secure unprivileged data access * @param qos optional QoS, defaults to 0 * @param region optional region, defaults to 0 + * @param user optional user, defaults to 0 */ class WriteTransaction( val addr: BigInt, @@ -42,7 +43,8 @@ class WriteTransaction( val cache: UInt = MemoryEncodings.DeviceNonbuf, val prot: UInt = ProtectionEncodings.DataNsecUpriv, val qos: UInt = 0.U, - val region: UInt = 0.U) extends Transaction { + val region: UInt = 0.U, + val user: UInt = 0.U) extends Transaction { private[this] val numBytes = 1 << size private[this] val dtsize = numBytes * data.length private[this] val lowerBoundary = (addr / dtsize) * dtsize @@ -94,7 +96,7 @@ class WriteTransaction( count += 1 /** Return data to write */ - (data(count-1).U, strb, complete.B) + (data(count-1).U, strb, complete.B, user) } def complete = data.length == count } @@ -111,6 +113,7 @@ class WriteTransaction( * @param prot optional protection type, defaults to non-secure unprivileged data access * @param qos optional QoS, defaults to 0 * @param region optional region, defaults to 0 + * @param user optional user, defaults to 0 */ class ReadTransaction( val addr: BigInt, @@ -122,7 +125,8 @@ class ReadTransaction( val cache: UInt = MemoryEncodings.DeviceNonbuf, val prot: UInt = ProtectionEncodings.DataNsecUpriv, val qos: UInt = 0.U, - val region: UInt = 0.U) extends Transaction { + val region: UInt = 0.U, + val user: UInt = 0.U) extends Transaction { var data = Seq[BigInt]() private[this] var _addrSent = false