@@ -6,11 +6,11 @@ | |||
<parameter name="maxFileLength"><![CDATA[800]]></parameter> | |||
</parameters> | |||
</check> | |||
<check level="warning" class="org.scalastyle.file.HeaderMatchesChecker" enabled="true"> | |||
<!--<check level="warning" class="org.scalastyle.file.HeaderMatchesChecker" enabled="true"> | |||
<parameters> | |||
<parameter name="header"><![CDATA[// See README.md for license details.]]></parameter> | |||
</parameters> | |||
</check> | |||
</check>--> | |||
<check level="warning" class="org.scalastyle.scalariform.SpacesAfterPlusChecker" enabled="true"></check> | |||
<check level="warning" class="org.scalastyle.file.WhitespaceEndOfLineChecker" enabled="true"></check> | |||
<check level="warning" class="org.scalastyle.scalariform.SpacesBeforePlusChecker" enabled="true"></check> | |||
@@ -1,39 +1,40 @@ | |||
package varec.axi4 | |||
/** Provides classes for dealing with AXI4 protocol. | |||
* | |||
* See ARM IHI 0022F.b (ID122117) | |||
* AMBA® AXI and ACE Protocol Specification (AXI3, AXI4, AXI5, ACE and ACE5) | |||
* at https://developer.arm.com/docs/ihi0022/fb | |||
* See ARM IHI 0022F.b (ID122117) | |||
* AMBA® AXI and ACE Protocol Specification (AXI3, AXI4, AXI5, ACE and ACE5) | |||
* at https://developer.arm.com/docs/ihi0022/fb | |||
* | |||
* Some encodings are implemented in AxiConfig. | |||
* Some encodings are implemented in AxiConfig. | |||
* | |||
* When handling unaligned read/write in AXI4, | |||
* see the following example: | |||
* 4-byte burst size, data represented using | |||
* hex numbers, little endian, and "-" for don't-care. | |||
* When handling unaligned read/write in AXI4, | |||
* see the following example: | |||
* 4-byte burst size, data represented using | |||
* hex numbers, little endian, and "-" for don't-care. | |||
* | |||
* 0x4 0x7 0x8 0xb 0xc 0xf | |||
* initial | cc cc cc cc | cc cc cc cc | cc cc cc cc | | |||
* target | cc cc cc 0d | 10 12 14 18 | 1a 1c cc cc | | |||
* 0x4 0x7 0x8 0xb 0xc 0xf | |||
* initial | cc cc cc cc | cc cc cc cc | cc cc cc cc | | |||
* target | cc cc cc 0d | 10 12 14 18 | 1a 1c cc cc | | |||
* | |||
* To write the target content in memory, | |||
* we need three write transfers in a burst: | |||
* data 0x0d------ for the 1st transfer starting at address 0x7; | |||
* data 0x18141210 for the 2nd transfer in the burst; | |||
* data 0x----1c1a for the last transfer with strobe 0x0011. | |||
* To write the target content in memory, | |||
* we need three write transfers in a burst: | |||
* data 0x0d------ for the 1st transfer starting at address 0x7; | |||
* data 0x18141210 for the 2nd transfer in the burst; | |||
* data 0x----1c1a for the last transfer with strobe 0x0011. | |||
* | |||
* To read the target content from memory, | |||
* we need three read transfers in a burst: | |||
* data 0x0d------ from the 1st transfer starting at address 0x7 | |||
* (or data 0x0dcc----, 0x0dcccc--, 0x0dcccccc for addresses 0x6, 0x5, 0x4, respectively); | |||
* data 0x18141210 from the 2nd transfer in the burst; | |||
* data 0xcccc1c1a from the last transfer (and drop the leading two cc's yourself). | |||
* To read the target content from memory, | |||
* we need three read transfers in a burst: | |||
* data 0x0d------ from the 1st transfer starting at address 0x7 | |||
* (or data 0x0dcc----, 0x0dcccc--, 0x0dcccccc for addresses 0x6, 0x5, 0x4, respectively); | |||
* data 0x18141210 from the 2nd transfer in the burst; | |||
* data 0xcccc1c1a from the last transfer (and drop the leading two cc's yourself). | |||
*/ | |||
import chisel3._ | |||
import chisel3.util._ | |||
class AxiMasterIO(val addr_width: Int, val data_width: Int) extends TraitAxiMasterIO { | |||
class AxiMasterIO(val addr_width: Int, val data_width: Int) extends AxiMasterIOTrait { | |||
val read_addr = new AxiAddressIO(UInt(addr_width.W)) | |||
val read_data = Flipped(new AxiReadDataIO(UInt(data_width.W))) | |||
val write_addr = new AxiAddressIO(UInt(addr_width.W)) | |||
@@ -41,7 +42,7 @@ class AxiMasterIO(val addr_width: Int, val data_width: Int) extends TraitAxiMast | |||
val write_resp = Flipped(new AxiWriteResponseIO(UInt(Axi4Config.Resp.width.W))) | |||
} | |||
class AxiMasterReadIO(val addr_width: Int, val data_width: Int) extends TraitAxiMasterReadIO { | |||
class AxiMasterReadIO(val addr_width: Int, val data_width: Int) extends AxiMasterReadIOTrait { | |||
val read_addr = new AxiAddressIO(UInt(addr_width.W)) | |||
val read_data = Flipped(new AxiReadDataIO(UInt(data_width.W))) | |||
@@ -52,7 +53,7 @@ class AxiMasterReadIO(val addr_width: Int, val data_width: Int) extends TraitAxi | |||
override def cloneType: this.type = new AxiMasterReadIO(addr_width, data_width).asInstanceOf[this.type] | |||
} | |||
class AxiMasterWriteIO(val addr_width: Int, val data_width: Int) extends TraitAxiMasterWriteIO { | |||
class AxiMasterWriteIO(val addr_width: Int, val data_width: Int) extends AxiMasterWriteIOTrait { | |||
val write_addr = new AxiAddressIO(UInt(addr_width.W)) | |||
val write_data = new AxiWriteDataIO(UInt(data_width.W)) | |||
val write_resp = Flipped(new AxiWriteResponseIO(UInt(Axi4Config.Resp.width.W))) | |||
@@ -62,23 +63,24 @@ class AxiMasterWriteIO(val addr_width: Int, val data_width: Int) extends TraitAx | |||
} | |||
} | |||
trait TraitAxiMasterIO extends Bundle with TraitAxiMasterWriteIO with TraitAxiMasterReadIO { | |||
trait AxiMasterIOTrait extends Bundle with AxiMasterWriteIOTrait with AxiMasterReadIOTrait { | |||
override def mInit() { | |||
super[TraitAxiMasterReadIO].mInit() | |||
super[TraitAxiMasterWriteIO].mInit() | |||
super[AxiMasterReadIOTrait].mInit() | |||
super[AxiMasterWriteIOTrait].mInit() | |||
} | |||
override def sInit() { | |||
super[TraitAxiMasterReadIO].sInit() | |||
super[TraitAxiMasterWriteIO].sInit() | |||
super[AxiMasterReadIOTrait].sInit() | |||
super[AxiMasterWriteIOTrait].sInit() | |||
} | |||
override def <>(that: TraitAxiMasterIO) { | |||
super[TraitAxiMasterReadIO].<>(that) | |||
super[TraitAxiMasterWriteIO].<>(that) | |||
override def <>(that: AxiMasterIOTrait) { | |||
super[AxiMasterReadIOTrait].<>(that) | |||
super[AxiMasterWriteIOTrait].<>(that) | |||
} | |||
} | |||
trait TraitAxiMasterReadIO extends Bundle { | |||
trait AxiMasterReadIOTrait extends Bundle { | |||
val addr_width: Int | |||
val data_width: Int | |||
val read_addr: AxiAddressIO | |||
@@ -94,17 +96,18 @@ trait TraitAxiMasterReadIO extends Bundle { | |||
read_data.sInit() | |||
} | |||
def <>(that: TraitAxiMasterIO) { | |||
def <>(that: AxiMasterIOTrait) { | |||
this.read_addr <> that.read_addr | |||
this.read_data <> that.read_data | |||
} | |||
def <>(that: TraitAxiMasterReadIO) { | |||
def <>(that: AxiMasterReadIOTrait) { | |||
this.read_addr <> that.read_addr | |||
this.read_data <> that.read_data | |||
} | |||
} | |||
trait TraitAxiMasterWriteIO extends Bundle { | |||
trait AxiMasterWriteIOTrait extends Bundle { | |||
val addr_width: Int | |||
val data_width: Int | |||
val write_addr: AxiAddressIO | |||
@@ -123,12 +126,13 @@ trait TraitAxiMasterWriteIO extends Bundle { | |||
write_resp.sInit() | |||
} | |||
def <>(that: TraitAxiMasterIO) { | |||
def <>(that: AxiMasterIOTrait) { | |||
this.write_addr <> that.write_addr | |||
this.write_data <> that.write_data | |||
this.write_resp <> that.write_resp | |||
} | |||
def <>(that: TraitAxiMasterWriteIO) { | |||
def <>(that: AxiMasterWriteIOTrait) { | |||
this.write_addr <> that.write_addr | |||
this.write_data <> that.write_data | |||
this.write_resp <> that.write_resp | |||
@@ -155,18 +159,22 @@ class AxiLiteSlaveIO(val addr_width: Int, val data_width: Int) extends Bundle { | |||
// AMBA® AXI and ACE Protocol Specification (AXI3, AXI4, AXI5, ACE and ACE5) | |||
// at https://developer.arm.com/docs/ihi0022/fb | |||
object Axi4Config { | |||
object Len { | |||
// A3.4.1 Address structure: Burst length | |||
val width = 8 | |||
def apply(length: UInt): UInt = { | |||
val code = WireDefault(0.U(width.W)) | |||
code := length - 1.U | |||
return code | |||
} | |||
} | |||
object Size { | |||
// Table A3-2 Burst size encoding | |||
val width = 3 | |||
def apply(bytes: Int): UInt = bytes match { | |||
case 1 => "b000".U(3.W) | |||
case 2 => "b001".U(3.W) | |||
@@ -178,6 +186,7 @@ object Axi4Config { | |||
case 128 => "b111".U(3.W) | |||
} | |||
} | |||
object Burst { | |||
// Table A3-3 Burst type encoding | |||
val width = 2 | |||
@@ -186,6 +195,7 @@ object Axi4Config { | |||
val WRAP = "b10".U(2.W) | |||
val RESERVED = "b11".U(2.W) | |||
} | |||
object Resp { | |||
// Table A3-4 RRESP and BRESP encoding | |||
val width = 2 | |||
@@ -194,6 +204,7 @@ object Axi4Config { | |||
val SLVERR = "b10".U(2.W) | |||
val DECERR = "b11".U(2.W) | |||
} | |||
trait CacheAx { | |||
// Table A4-5 Memory type encoding | |||
val width = 4 | |||
@@ -202,8 +213,10 @@ object Axi4Config { | |||
val NORMAL_NON_CACHEABLE_NON_BUFFERABLE = "b0010".U(4.W) | |||
val NORMAL_NON_CACHEABLE_BUFFERABLE = "b0011".U(4.W) | |||
} | |||
object Cache extends CacheAx { | |||
} | |||
object CacheAr extends CacheAx { | |||
val WRITE_THROUGH_NO_ALLOCATE = "b1010".U(4.W) | |||
val WRITE_THROUGH_READ_ALLOCATE = "b1110".U(4.W) | |||
@@ -214,6 +227,7 @@ object Axi4Config { | |||
val WRITE_BACK_WRITE_ALLOCATE = "b1011".U(4.W) | |||
val WRITE_BACK_READ_AND_WRITE_ALLOCATE = "b1111".U(4.W) | |||
} | |||
object cacheAw extends CacheAx { | |||
val WRITE_THROUGH_NO_ALLOCATE = "b0110".U(4.W) | |||
val WRITE_THROUGH_READ_ALLOCATE = "b0110".U(4.W) | |||
@@ -224,6 +238,7 @@ object Axi4Config { | |||
val WRITE_BACK_WRITE_ALLOCATE = "b1111".U(4.W) | |||
val WRITE_BACK_READ_AND_WRITE_ALLOCATE = "b1111".U(4.W) | |||
} | |||
object Prot { | |||
val width = 3 | |||
// Table A4-6 Protection encoding | |||
@@ -237,6 +252,7 @@ object Axi4Config { | |||
val DATA = "b000".U(3.W) | |||
val INSTRUCTION = "b100".U(3.W) | |||
} | |||
object Lock { | |||
// Table A7-2 AXI4 atomic access encoding | |||
val width = 1 | |||
@@ -251,76 +267,91 @@ object Axi4Config { | |||
val LOCKDED = "b10".U(2.W) | |||
val RESERVED = "b11".U(2.W) | |||
} | |||
} | |||
} | |||
// Table B1-1 shows the required signals on an AXI4-Lite interface. //////////// | |||
trait TraitAxiLiteAddressIO extends DecoupledIO[UInt] { | |||
trait AxiLiteAddressIOTrait extends DecoupledIO[UInt] { | |||
// directions in the perspective of master (address source) | |||
def addr: UInt = bits | |||
val prot = Output(UInt(Axi4Config.Prot.width.W)) | |||
def mInit() { | |||
this.noenq() | |||
prot := {import Axi4Config.Prot._; UNPRIVILEGED|SECURE|DATA} | |||
prot := { | |||
import Axi4Config.Prot._; UNPRIVILEGED | SECURE | DATA | |||
} | |||
} | |||
def sInit() { | |||
this.nodeq() | |||
} | |||
} | |||
class AxiLiteAddressIO(gen: UInt) extends DecoupledIO(gen) with TraitAxiLiteAddressIO { | |||
class AxiLiteAddressIO(gen: UInt) extends DecoupledIO(gen) with AxiLiteAddressIOTrait { | |||
override def cloneType: this.type = new AxiLiteAddressIO(gen).asInstanceOf[this.type] | |||
} | |||
trait TraitAxiLiteReadDataIO extends DecoupledIO[UInt] { | |||
trait AxiLiteReadDataIOTrait extends DecoupledIO[UInt] { | |||
// directions in the perspective of slave (read data source) | |||
def data: UInt = bits | |||
val resp = Output(UInt(Axi4Config.Resp.width.W)) | |||
def mInit() { | |||
this.nodeq() | |||
} | |||
def sInit() { | |||
this.noenq() | |||
resp := DontCare | |||
} | |||
} | |||
class AxiLiteReadDataIO(gen: UInt) extends DecoupledIO(gen) with TraitAxiLiteReadDataIO { | |||
class AxiLiteReadDataIO(gen: UInt) extends DecoupledIO(gen) with AxiLiteReadDataIOTrait { | |||
override def cloneType: this.type = new AxiLiteReadDataIO(gen).asInstanceOf[this.type] | |||
} | |||
trait TraitAxiLiteWriteDataIO extends DecoupledIO[UInt] { | |||
trait AxiLiteWriteDataIOTrait extends DecoupledIO[UInt] { | |||
// directions in the perspective of master (write data source) | |||
private val strb_width = bits.getWidth / 8 | |||
def data: UInt = bits | |||
val strb = Output(UInt(strb_width.W)) | |||
def mInit() { | |||
this.noenq() | |||
strb := ~0.U(strb_width.W) // bit-wise not | |||
} | |||
def sInit() { | |||
this.nodeq() | |||
} | |||
} | |||
class AxiLiteWriteDataIO(gen: UInt) extends DecoupledIO(gen) with TraitAxiLiteWriteDataIO { | |||
class AxiLiteWriteDataIO(gen: UInt) extends DecoupledIO(gen) with AxiLiteWriteDataIOTrait { | |||
override def cloneType: this.type = new AxiLiteWriteDataIO(gen).asInstanceOf[this.type] | |||
} | |||
trait TraitAxiLiteWriteResponseIO extends DecoupledIO[UInt] { | |||
trait AxiLiteWriteResponseIOTrait extends DecoupledIO[UInt] { | |||
// directions in the perspective of slave (write response source) | |||
def resp: UInt = bits | |||
def mInit() { | |||
this.nodeq() | |||
} | |||
def sInit() { | |||
this.noenq() | |||
} | |||
} | |||
class AxiLiteWriteResponseIO(gen: UInt) extends DecoupledIO(gen) with TraitAxiLiteWriteResponseIO { | |||
class AxiLiteWriteResponseIO(gen: UInt) extends DecoupledIO(gen) with AxiLiteWriteResponseIOTrait { | |||
override def cloneType: this.type = new AxiLiteWriteResponseIO(gen).asInstanceOf[this.type] | |||
} | |||
@@ -337,7 +368,7 @@ trait AxiIdentifier { | |||
} | |||
} | |||
class AxiAddressIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with TraitAxiLiteAddressIO { | |||
class AxiAddressIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with AxiLiteAddressIOTrait { | |||
// Table A2-2 Write address channel signals | |||
// Table A2-5 Read address channel signals | |||
val len = Output(UInt(Axi4Config.Len.width.W)) // === #transfers minus one | |||
@@ -351,7 +382,7 @@ class AxiAddressIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with T | |||
override def mInit() { | |||
super[AxiIdentifier].init() | |||
super[TraitAxiLiteAddressIO].mInit() | |||
super[AxiLiteAddressIOTrait].mInit() | |||
len := 0.U | |||
size := Axi4Config.Size(2) | |||
@@ -367,48 +398,53 @@ class AxiAddressIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with T | |||
def setLen(len: UInt) { | |||
this.len := len - 1.U | |||
} | |||
def setSize(size: Int) { | |||
this.size := Axi4Config.Size(size) | |||
} | |||
// slave mode | |||
def getLen(): UInt = (len + 1.U((Axi4Config.Len.width + 1).W)) | |||
def getSize(): UInt = (1.U << size) | |||
override def cloneType: this.type = new AxiAddressIO(gen).asInstanceOf[this.type] | |||
} | |||
class AxiReadDataIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with TraitAxiLiteReadDataIO { | |||
class AxiReadDataIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with AxiLiteReadDataIOTrait { | |||
// Table A2-6 Read data channel signals | |||
val last = Output(Bool()) | |||
override def sInit() { | |||
super[AxiIdentifier].init() | |||
super[TraitAxiLiteReadDataIO].sInit() | |||
super[AxiLiteReadDataIOTrait].sInit() | |||
last := false.B | |||
} | |||
override def cloneType: this.type = new AxiReadDataIO(gen).asInstanceOf[this.type] | |||
} | |||
class AxiWriteDataIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with TraitAxiLiteWriteDataIO { | |||
class AxiWriteDataIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with AxiLiteWriteDataIOTrait { | |||
// Table A2-3 Write data channel signals | |||
val last = Output(Bool()) | |||
override def mInit() { | |||
super[AxiIdentifier].init() | |||
super[TraitAxiLiteWriteDataIO].mInit() | |||
super[AxiLiteWriteDataIOTrait].mInit() | |||
last := false.B | |||
} | |||
override def cloneType: this.type = new AxiWriteDataIO(gen).asInstanceOf[this.type] | |||
} | |||
class AxiWriteResponseIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with TraitAxiLiteWriteResponseIO { | |||
class AxiWriteResponseIO(gen: UInt) extends DecoupledIO(gen) with AxiIdentifier with AxiLiteWriteResponseIOTrait { | |||
// Table A2-4 Write response channel signals | |||
override def sInit() { | |||
super[AxiIdentifier].init() | |||
super[TraitAxiLiteWriteResponseIO].sInit() | |||
super[AxiLiteWriteResponseIOTrait].sInit() | |||
} | |||
override def cloneType: this.type = new AxiWriteResponseIO(gen).asInstanceOf[this.type] | |||
} | |||
@@ -4,7 +4,8 @@ import chisel3._ | |||
import chisel3.util._ | |||
object MathForPowerOfTwo { | |||
def isPowerOfTwo(x: Int): Boolean = (x != 0 && (x & (x-1)) == 0) | |||
def isPowerOfTwo(x: Int): Boolean = (x != 0 && (x & (x - 1)) == 0) | |||
def mask(x: Int): UInt = ~0.U(log2Ceil(x).W) | |||
implicit class forPowerOfTwoMultiplication(x: UInt) { | |||
@@ -26,17 +27,17 @@ object MathForPowerOfTwo { | |||
/** Modulo operator | |||
* | |||
* bit width reduced to log(y) | |||
* bit width reduced to log(y) | |||
*/ | |||
def #%(y: Int): UInt = { | |||
assert(isPowerOfTwo(y)) | |||
(x & mask(y))(log2Ceil(y) - 1, 0) | |||
(x & mask(y)) (log2Ceil(y) - 1, 0) | |||
} | |||
/** Compute the greatest multiple of y before x | |||
* | |||
* x #^ y === floor(x / y) * y | |||
*/ | |||
* x #^ y === floor(x / y) * y | |||
**/ | |||
def #^(y: Int): UInt = { | |||
assert(isPowerOfTwo(y)) | |||
x & ~(mask(y) | 0.U(x.getWidth.W)) | |||
@@ -44,11 +45,12 @@ object MathForPowerOfTwo { | |||
/** Compute the least multiple of y after x | |||
* | |||
* x #^^ y === ceil(x / y) * y | |||
* x #^^ y === ceil(x / y) * y | |||
*/ | |||
def #^^(y: Int): UInt = { | |||
assert(isPowerOfTwo(y)) | |||
(x | mask(y)) + 1.U | |||
} | |||
} | |||
} |
@@ -8,12 +8,14 @@ import varec.util.Constants._ | |||
abstract class XclControlProcess { | |||
def isActive(): Bool | |||
def getStart(): Bool | |||
def setDone(): Unit | |||
} | |||
object XclControl { | |||
def apply(s_axi: AxiLiteSlaveIO, userAddrToReg: Map[UInt,UInt]): XclControlProcess = new XclControlProcess { | |||
def apply(s_axi: AxiLiteSlaveIO, userAddrToReg: Map[UInt, UInt]): XclControlProcess = new XclControlProcess { | |||
val addr_width = s_axi.addr_width | |||
val data_width = s_axi.data_width | |||
@@ -23,11 +25,11 @@ object XclControl { | |||
val ready = RegInit(true.B) // ready at the beginning | |||
val auto_restart = RegInit(false.B) | |||
def isActive(): Bool = (! idle) | |||
def isActive(): Bool = (!idle) | |||
def getStart(): Bool = { | |||
val cond = ready && start | |||
when (cond) { | |||
when(cond) { | |||
start := false.B // clear on handshake | |||
done := false.B | |||
idle := false.B | |||
@@ -43,7 +45,7 @@ object XclControl { | |||
ready := true.B | |||
} | |||
when (ready) { | |||
when(ready) { | |||
start := auto_restart // copy and paste from the Xilinx reference design | |||
} | |||
@@ -103,31 +105,31 @@ object XclControl { | |||
def processWriteRequests() { | |||
val request_gen = new WriteRequest(UInt(addr_width.W), UInt(data_width.W)) | |||
val request = write_slave.out.deq().asTypeOf(request_gen) | |||
when (write_slave.out.fire) { | |||
when(write_slave.out.fire) { | |||
val wmask = WireDefault(request.strb.asBools | |||
.map(bit => Fill(BYTE_WIDTH, bit)) | |||
.reverse.reduce(_ ## _)) | |||
for ((addr, reg) <- addrToReg) { | |||
when (request.addr === addr) { // common rule | |||
when(request.addr === addr) { // common rule | |||
reg := (request.data & wmask) | (reg & ~wmask) | |||
} | |||
} | |||
when (request.addr === SysAddr.AP_CTRL && request.strb(0).asBool) { // special rule | |||
when(request.addr === SysAddr.AP_CTRL && request.strb(0).asBool) { // special rule | |||
// Warning: check the Xilinx reference design | |||
start := request.data(0) | |||
auto_restart := request.data(7) | |||
} | |||
val isr_wire = WireDefault(isr_ctrl.asTypeOf(Vec(isr_ctrl.getWidth, Bool()))) // special rule | |||
when (ier_ctrl(0) && done) { | |||
when(ier_ctrl(0) && done) { | |||
isr_wire(0) := true.B | |||
} .elsewhen (request.addr === SysAddr.ISR_CTRL && request.strb(0).asBool) { | |||
}.elsewhen(request.addr === SysAddr.ISR_CTRL && request.strb(0).asBool) { | |||
isr_wire(0) := request.data(0) | |||
} | |||
when (ier_ctrl(1) && ready) { | |||
when(ier_ctrl(1) && ready) { | |||
isr_wire(1) := true.B | |||
} .elsewhen (request.addr === SysAddr.ISR_CTRL && request.strb(0).asBool) { | |||
}.elsewhen(request.addr === SysAddr.ISR_CTRL && request.strb(0).asBool) { | |||
isr_wire(1) := request.data(1) | |||
} | |||
isr_ctrl := isr_wire.asTypeOf(isr_ctrl) | |||
@@ -139,26 +141,26 @@ object XclControl { | |||
val state = RegInit(s_fetch) | |||
val raddr = Reg(UInt(addr_width.W)) | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
raddr := read_slave.addr.deq() | |||
when (read_slave.addr.fire) { | |||
when(read_slave.addr.fire) { | |||
state := s_exec | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
val word = WireDefault(0.U(data_width.W)) | |||
for ((addr, reg) <- addrToReg) { | |||
when (raddr === addr) { // common rule | |||
when(raddr === addr) { // common rule | |||
word := reg | |||
} | |||
} | |||
when (raddr === SysAddr.AP_CTRL) { // special rule | |||
when(raddr === SysAddr.AP_CTRL) { // special rule | |||
word := ap_ctrl | |||
done := false.B // clear on read | |||
} | |||
read_slave.data.enq(word) | |||
when (read_slave.data.fire) { | |||
when(read_slave.data.fire) { | |||
state := s_fetch | |||
} | |||
} |
@@ -2,19 +2,20 @@ package varec.util | |||
import chisel3._ | |||
import chisel3.util._ | |||
import varec.axi4.{Axi4Config, AxiLiteSlaveIO, AxiMasterIO, AxiMasterReadIO, AxiMasterWriteIO, TraitAxiMasterReadIO} | |||
import varec.axi4.{Axi4Config, AxiLiteSlaveIO, AxiMasterIO, AxiMasterReadIO, AxiMasterWriteIO, AxiMasterReadIOTrait} | |||
import varec.util.Constants._ | |||
import varec.math.MathForPowerOfTwo._ | |||
class WriteRequest[T<:Data](addr_gen: T, data_gen: T) extends Bundle { | |||
class WriteRequest[T <: Data](addr_gen: T, data_gen: T) extends Bundle { | |||
val addr = addr_gen | |||
val data = data_gen | |||
require(data.getWidth % BYTE_WIDTH == 0) | |||
val strb = UInt((data.getWidth / BYTE_WIDTH).W) | |||
override def cloneType: this.type = new WriteRequest(addr_gen, data_gen).asInstanceOf[this.type] | |||
} | |||
class ReadArbiter(n: Int, bus: TraitAxiMasterReadIO) extends Module { | |||
class ReadArbiter(n: Int, bus: AxiMasterReadIOTrait) extends Module { | |||
val io = IO(new Bundle { | |||
val server = new AxiMasterReadIO(bus.addr_width, bus.data_width) | |||
val client = Vec(n, Flipped(new AxiMasterReadIO(bus.addr_width, bus.data_width))) | |||
@@ -25,14 +26,14 @@ class ReadArbiter(n: Int, bus: TraitAxiMasterReadIO) extends Module { | |||
val s_idle = io.client.length.U | |||
val state = RegInit(s_idle) | |||
when (state === s_idle) { | |||
when(state === s_idle) { | |||
nextState() | |||
} | |||
for (i <- 0 until io.client.length) { | |||
when (state === i.U) { | |||
when(state === i.U) { | |||
io.client(i) <> io.server | |||
when (io.server.read_data.last && io.server.read_data.fire) { | |||
when(io.server.read_data.last && io.server.read_data.fire) { | |||
nextState() | |||
} | |||
} | |||
@@ -40,16 +41,16 @@ class ReadArbiter(n: Int, bus: TraitAxiMasterReadIO) extends Module { | |||
def nextState() { | |||
val onehot = PriorityEncoderOH(Cat((0 until io.client.length).map(i => io.client(i).read_addr.valid).reverse)) | |||
when (onehot === 0.U) { | |||
when(onehot === 0.U) { | |||
state := s_idle | |||
} .otherwise { | |||
}.otherwise { | |||
state := OHToUInt(onehot) | |||
} | |||
} | |||
} | |||
object BusReader { | |||
def apply(bus_io: TraitAxiMasterReadIO, mem_io: TraitMemWriteIO) = new { | |||
def apply(bus_io: AxiMasterReadIOTrait, mem_io: MemWriteIOTrait) = new { | |||
val bus_width = bus_io.read_data.bits.getWidth | |||
val mem_width = mem_io.din.getWidth | |||
@@ -63,7 +64,7 @@ object BusReader { | |||
* | |||
* @param dst_mem_base the base address on mem | |||
* @param src_bus_base the base address on bus | |||
* @param size the number of bytes to transfer | |||
* @param size the number of bytes to transfer | |||
*/ | |||
def start(dst_mem_base: UInt, src_bus_base: UInt, size: UInt) { | |||
val bus_size = bus_width / BYTE_WIDTH | |||
@@ -80,16 +81,16 @@ object BusReader { | |||
deq_bus.start(src_bus_base, bus_len) | |||
} | |||
def run() { | |||
def run(): Unit = { | |||
connect() | |||
enq_mem.run() | |||
deq_bus.run() | |||
when (idle) { | |||
when(idle) { | |||
channel.reset() | |||
} | |||
} | |||
def connect() { | |||
def connect(): Unit = { | |||
enq_mem.in <> channel.out | |||
channel.in <> deq_bus.out | |||
} | |||
@@ -162,50 +163,50 @@ object BusLiteWriteSlave { | |||
def out = obuf.io.deq | |||
def idle() = (state === s_fetch && ! bus_io.write_addr.valid) | |||
def idle() = (state === s_fetch && !bus_io.write_addr.valid) | |||
def run() { | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
pullAddr() | |||
} | |||
when (state === s_load) { | |||
when(state === s_load) { | |||
data := bus_io.write_data.deq() | |||
when (bus_io.write_data.fire) { | |||
when(bus_io.write_data.fire) { | |||
strb := bus_io.write_data.strb | |||
state := s_resp | |||
} | |||
} | |||
when (state === s_resp) { | |||
when(state === s_resp) { | |||
bus_io.write_resp.enq(Axi4Config.Resp.OKAY) | |||
when (bus_io.write_resp.fire) { | |||
when(bus_io.write_resp.fire) { | |||
state := s_exec | |||
pushRequest() | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
pushRequest() | |||
} | |||
} | |||
protected def pullAddr() { | |||
addr := bus_io.write_addr.deq() | |||
when (bus_io.write_addr.fire) { | |||
when(bus_io.write_addr.fire) { | |||
state := s_load | |||
addr := bus_io.write_addr.bits | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_fetch | |||
} | |||
} | |||
protected def pushRequest() { | |||
obuf.io.enq.enq(Cat(addr, data, strb)) | |||
when (obuf.io.enq.fire) { | |||
when(obuf.io.enq.fire) { | |||
state := s_fetch | |||
pullAddr() | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_exec | |||
} | |||
} | |||
@@ -226,9 +227,10 @@ object BusLiteReadSlave { | |||
ibuf.io.deq.nodeq() | |||
def addr = obuf.io.deq | |||
def data = ibuf.io.enq | |||
def idle() = (! bus_io.read_addr.valid && ! bus_io.read_data.valid) | |||
def idle() = (!bus_io.read_addr.valid && !bus_io.read_data.valid) | |||
def run() { | |||
// |
@@ -2,9 +2,9 @@ package varec.util | |||
import chisel3._ | |||
import chisel3.util._ | |||
import varec.axi4.{Axi4Config, AxiMasterIO, AxiMasterReadIO, AxiMasterWriteIO, TraitAxiMasterReadIO} | |||
import varec.axi4.{Axi4Config, AxiMasterIO, AxiMasterReadIO, AxiMasterWriteIO} | |||
@deprecated("use DeqBus or EnqBus instead","") | |||
@deprecated("use DeqBus or EnqBus instead", "") | |||
object DecoupledBus { | |||
def apply(bus: AxiMasterReadIO, enq: DecoupledIO[UInt]) = new { | |||
@@ -24,34 +24,35 @@ object DecoupledBus { | |||
def read(base: UInt, len: UInt) { | |||
val counter = RegInit(0.U(len_width)) | |||
when (state === s_start) { | |||
when(state === s_start) { | |||
bus.read_addr.setLen(len) | |||
bus.read_addr.setSize(data_width/8) | |||
bus.read_addr.setSize(data_width / 8) | |||
bus.read_addr.enq(base) | |||
when (bus.read_addr.fire()) { | |||
when(bus.read_addr.fire()) { | |||
state := s_read | |||
counter := len-1.U | |||
assert(bus.read_addr.len === len-1.U) | |||
counter := len - 1.U | |||
assert(bus.read_addr.len === len - 1.U) | |||
} | |||
} | |||
when (state === s_read) { | |||
when(state === s_read) { | |||
connect() | |||
when (bus.read_data.fire()) { | |||
when(bus.read_data.fire()) { | |||
counter := counter - 1.U | |||
when (bus.read_data.last) { | |||
when(bus.read_data.last) { | |||
state := s_idle | |||
assert(counter === 0.U) | |||
} | |||
} | |||
} | |||
when (state === s_idle) { | |||
when(state === s_idle) { | |||
} | |||
} | |||
def connect() { | |||
bus.read_data.ready <> enq.ready | |||
bus.read_data.valid <> enq.valid | |||
@@ -70,44 +71,46 @@ object DecoupledBus { | |||
def idle() = (state === s_idle) | |||
def start() { state := s_start } | |||
def start() { | |||
state := s_start | |||
} | |||
def write(base: UInt, len: UInt) { | |||
val counter = RegInit(0.U(len_width.W)) | |||
when (state === s_start) { | |||
when(state === s_start) { | |||
bus.write_addr.setLen(len) | |||
bus.write_addr.setSize(data_width/8) | |||
bus.write_addr.setSize(data_width / 8) | |||
bus.write_addr.enq(base) | |||
when (bus.write_addr.fire()) { | |||
when(bus.write_addr.fire()) { | |||
state := s_write | |||
counter := bus.write_addr.len | |||
assert(bus.write_addr.len === len-1.U) | |||
assert(bus.write_addr.len === len - 1.U) | |||
} | |||
} | |||
when (state === s_write) { | |||
when(state === s_write) { | |||
connect() | |||
when (bus.write_data.fire()) { | |||
when (counter === 0.U) { | |||
when(bus.write_data.fire()) { | |||
when(counter === 0.U) { | |||
state := s_resp | |||
bus.write_data.last := true.B | |||
} .otherwise { | |||
}.otherwise { | |||
counter := counter - 1.U | |||
} | |||
} | |||
} | |||
when (state === s_resp) { | |||
when(state === s_resp) { | |||
val resp = bus.write_resp.deq() | |||
when (bus.write_resp.fire()) { | |||
when(bus.write_resp.fire()) { | |||
state := s_idle | |||
assert(counter === 0.U) | |||
assert(resp === Axi4Config.Resp.OKAY) | |||
} | |||
} | |||
when (state === idle) { | |||
when(state === idle) { | |||
} | |||
} | |||
@@ -4,7 +4,7 @@ import chisel3._ | |||
import chisel3.util._ | |||
object Handshake { | |||
def apply[T<:Data](gen: T): Handshake[T] = { | |||
def apply[T <: Data](gen: T): Handshake[T] = { | |||
val self = Module(new Handshake(gen)) | |||
val io = self.io | |||
io.enq.noenq() | |||
@@ -12,7 +12,8 @@ object Handshake { | |||
return self | |||
} | |||
} | |||
class Handshake[T<:Data](gen: T) extends Module { | |||
class Handshake[T <: Data](gen: T) extends Module { | |||
val io = IO(new Bundle { | |||
val enq = Flipped(EnqIO(gen)) | |||
val deq = Flipped(DeqIO(gen)) | |||
@@ -28,14 +29,17 @@ object Channel { | |||
self.io.out.nodeq() | |||
def in = self.io.in | |||
def out = self.io.out | |||
def reset() { | |||
self.reset := true.B | |||
} | |||
def run() {} | |||
} | |||
} | |||
class Channel(out_width: Int, in_width: Int) extends Module { | |||
val io = IO(new Bundle { | |||
val in = Flipped(EnqIO(UInt(in_width.W))) | |||
@@ -59,9 +63,9 @@ class Channel(out_width: Int, in_width: Int) extends Module { | |||
io.out <> io.in | |||
case SplitOrConcat.Split => | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
val data = io.in.deq().asTypeOf(data_in) | |||
when (io.in.fire) { | |||
when(io.in.fire) { | |||
state := s_exec | |||
data_in := data | |||
assert(index === 0.U) | |||
@@ -69,16 +73,16 @@ class Channel(out_width: Int, in_width: Int) extends Module { | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
pushData(data_in(index)) | |||
} | |||
def pushData(data: UInt) { | |||
io.out.enq(data) | |||
when (io.out.fire) { | |||
when(io.out.fire) { | |||
val next_index = index + 1.U | |||
index := next_index | |||
when (next_index === manip.factor.U) { | |||
when(next_index === manip.factor.U) { | |||
state := s_fetch | |||
index := 0.U | |||
} | |||
@@ -86,13 +90,13 @@ class Channel(out_width: Int, in_width: Int) extends Module { | |||
} | |||
case SplitOrConcat.Concat => | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
pullData() | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
io.out.enq(data_out.asUInt) | |||
when (io.out.fire) { | |||
when(io.out.fire) { | |||
state := s_fetch | |||
assert(index === 0.U) | |||
pullData() | |||
@@ -101,11 +105,11 @@ class Channel(out_width: Int, in_width: Int) extends Module { | |||
def pullData() { | |||
val data = io.in.deq() | |||
when (io.in.fire) { | |||
when(io.in.fire) { | |||
data_out(index) := data | |||
val next_index = index + 1.U | |||
index := next_index | |||
when (next_index === manip.factor.U) { | |||
when(next_index === manip.factor.U) { | |||
state := s_exec | |||
index := 0.U | |||
} |
@@ -2,14 +2,14 @@ package varec.util | |||
import chisel3._ | |||
import chisel3.util._ | |||
import varec.axi4.{Axi4Config, AxiMasterReadIO, TraitAxiMasterReadIO} | |||
import varec.axi4.{Axi4Config, AxiMasterReadIO, AxiMasterReadIOTrait} | |||
import varec.util.Constants._ | |||
import varec.math.MathForPowerOfTwo._ | |||
/** A bus-reading process model for the DeqBus module. | |||
* | |||
* It wraps up the bus-reading protocol (e.g., AXI4) using the {@code start} and {@code run} methods | |||
* and generates an output handle {@code out} in the valid-ready protocol. | |||
* It wraps up the bus-reading protocol (e.g., AXI4) using the `start` and `run` methods | |||
* and generates an output handle `out` in the valid-ready protocol. | |||
*/ | |||
abstract class DeqBusProcess { | |||
/** The output handle in the valid-ready protocol. | |||
@@ -23,7 +23,7 @@ abstract class DeqBusProcess { | |||
/** Start the bus-reading process. | |||
* | |||
* @param base the base address | |||
* @param len the number of transfers, where #bytes == len * bus.read_data.bits.getWidth / BYTE_WIDTH | |||
* @param len the number of transfers, where #bytes == len * bus.read_data.bits.getWidth / BYTE_WIDTH | |||
*/ | |||
def start(base: UInt, len: UInt): Unit | |||
@@ -33,7 +33,7 @@ abstract class DeqBusProcess { | |||
} | |||
object DeqBus { | |||
def apply(bus: TraitAxiMasterReadIO): DeqBusProcess = new DeqBusProcess { | |||
def apply(bus: AxiMasterReadIOTrait): DeqBusProcess = new DeqBusProcess { | |||
val self = Module(new DeqBus(bus)) | |||
self.io.en := false.B | |||
@@ -69,7 +69,7 @@ object DeqBus { | |||
class DeqBus(addr_width: Int, data_width: Int) extends Module { | |||
val data_size = data_width / BYTE_WIDTH // #bytes per data item | |||
def this(bus_io: TraitAxiMasterReadIO) { | |||
def this(bus_io: AxiMasterReadIOTrait) { | |||
this(bus_io.read_addr.bits.getWidth, bus_io.read_data.bits.getWidth) | |||
} | |||
@@ -98,37 +98,37 @@ class DeqBus(addr_width: Int, data_width: Int) extends Module { | |||
io.idle := (state === s_fetch) && (remain === 0.U) | |||
when (io.en) { | |||
when (io.idle && io.start) { | |||
when(io.en) { | |||
when(io.idle && io.start) { | |||
state := s_fetch | |||
addr := io.base | |||
remain := io.len | |||
//printf("[DeqBus] start 0x%x %d\n", io.base, io.len) | |||
//printf("[DeqBus] start 0x%x %d\n", io.base, io.len) | |||
} | |||
when (state === s_fetch) { | |||
when (remain > 0.U) { | |||
when(state === s_fetch) { | |||
when(remain > 0.U) { | |||
val len = remain.min(burst_len) | |||
io.bus.read_addr.setLen(len) | |||
io.bus.read_addr.setSize(data_size) | |||
io.bus.read_addr.enq(addr) | |||
when (io.bus.read_addr.fire) { | |||
when(io.bus.read_addr.fire) { | |||
state := s_exec | |||
addr := addr + (len #* data_size) | |||
remain := remain - len | |||
burst_remain := len | |||
//printf("[DeqBus] read_addr fire len=%d data_size=%d addr=0x%x\n", len, (data_size).U, io.bus.read_addr.bits) | |||
//printf("[DeqBus] read_addr fire len=%d data_size=%d addr=0x%x\n", len, (data_size).U, io.bus.read_addr.bits) | |||
} | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
connect() | |||
when (io.bus.read_data.fire) { | |||
//printf("[DeqBus] data fire 0x%x\n", io.bus.read_data.bits) | |||
when(io.bus.read_data.fire) { | |||
//printf("[DeqBus] data fire 0x%x\n", io.bus.read_data.bits) | |||
val next_burst_remain = burst_remain - 1.U | |||
burst_remain := next_burst_remain | |||
when (io.bus.read_data.last) { | |||
when(io.bus.read_data.last) { | |||
state := s_fetch | |||
assert(next_burst_remain === 0.U) | |||
} |
@@ -6,7 +6,7 @@ import varec.util.Constants._ | |||
/** A memory-reading process model for the DeqMem module. | |||
* | |||
* It fetches data from on-chip memory and generate an outpu handle {@code out} | |||
* It fetches data from on-chip memory and generate an outpu handle `out` | |||
*/ | |||
abstract class DeqMemProcess { | |||
/** The output handle in the valid-ready protocol. | |||
@@ -19,8 +19,8 @@ abstract class DeqMemProcess { | |||
/** Start the memory-reading process. | |||
* | |||
* @param base the base address | |||
* @param len the number of transfers, where #bytes == len * mem.din.getWidth/8 | |||
* @param base the base address | |||
* @param len the number of transfers, where #bytes == len * mem.din.getWidth/8 | |||
* @param prepend prepends a few dummy data at the beginning | |||
*/ | |||
def start(base: UInt, len: UInt, prepend: UInt = 0.U): Unit | |||
@@ -31,7 +31,7 @@ abstract class DeqMemProcess { | |||
} | |||
object DeqMem { | |||
def apply(mem: TraitMemReadIO): DeqMemProcess = new DeqMemProcess { | |||
def apply(mem: MemReadIOTrait): DeqMemProcess = new DeqMemProcess { | |||
val self = Module(new DeqMem(mem)) | |||
self.io.out.nodeq() | |||
@@ -69,7 +69,7 @@ object DeqMem { | |||
} | |||
object EnqAddrDeqMem { | |||
def apply(enq_io: => DecoupledIO[UInt], mem_io: => TraitMemReadIO, deq_io: => DecoupledIO[UInt]) = new { | |||
def apply(enq_io: => DecoupledIO[UInt], mem_io: => MemReadIOTrait, deq_io: => DecoupledIO[UInt]) = new { | |||
val self = Module(new EnqAddrDeqMem(mem_io)) | |||
self.io.iaddr.noenq() | |||
@@ -92,7 +92,7 @@ object EnqAddrDeqMem { | |||
} | |||
} | |||
class DeqMem(mem_io: TraitMemReadIO) extends Module { | |||
class DeqMem(mem_io: MemReadIOTrait) extends Module { | |||
val mem_depth = mem_io.mem_depth | |||
val data_width = mem_io.dout.getWidth | |||
val addr_width = mem_io.addr.getWidth | |||
@@ -118,9 +118,11 @@ class DeqMem(mem_io: TraitMemReadIO) extends Module { | |||
val prepend = Reg(UInt(addr_width.W)) | |||
val iaddr_hs = Handshake(UInt(addr_width.W)) | |||
def iaddr: DecoupledIO[UInt] = iaddr_hs.io.enq | |||
val odata_hs = Handshake(UInt(data_width.W)) | |||
def odata: DecoupledIO[UInt] = odata_hs.io.deq | |||
val imo = EnqAddrDeqMem(iaddr_hs.io.deq, io.mem, odata_hs.io.enq) | |||
@@ -130,42 +132,42 @@ class DeqMem(mem_io: TraitMemReadIO) extends Module { | |||
io.idle := (state === s_idle) | |||
when (io.en) { | |||
when(io.en) { | |||
imo.run() | |||
when (io.idle && io.start) { | |||
when (io.prepend === 0.U) { | |||
when(io.idle && io.start) { | |||
when(io.prepend === 0.U) { | |||
state := s_fetch | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_wait | |||
} | |||
index := io.base | |||
len := io.len | |||
prepend := io.prepend | |||
//printf("[DeqMem] start base=0x%x len=%d\n", io.base, io.len) | |||
//printf("[DeqMem] start base=0x%x len=%d\n", io.base, io.len) | |||
} | |||
when (state === s_wait) { | |||
when (prepend === 0.U) { | |||
when(state === s_wait) { | |||
when(prepend === 0.U) { | |||
state := s_fetch | |||
} .otherwise { | |||
}.otherwise { | |||
io.out.bits := BigInt("cc" * (io.out.bits.getWidth / BYTE_WIDTH), 16).U | |||
io.out.valid := true.B | |||
when (io.out.fire) { | |||
//printf("[DeqMem] prepend 0x%x\n", io.out.bits) | |||
when(io.out.fire) { | |||
//printf("[DeqMem] prepend 0x%x\n", io.out.bits) | |||
prepend := prepend - 1.U | |||
} | |||
} | |||
} | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
fetch() | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
io.out.enq(data) | |||
when (io.out.fire) { | |||
//printf("[DeqMem] data 0x%x\n", io.out.bits) | |||
when(io.out.fire) { | |||
//printf("[DeqMem] data 0x%x\n", io.out.bits) | |||
fetch() | |||
} | |||
} | |||
@@ -173,26 +175,26 @@ class DeqMem(mem_io: TraitMemReadIO) extends Module { | |||
def fetch() { | |||
// enq addr | |||
when (len > 0.U) { | |||
when(len > 0.U) { | |||
iaddr.enq(index) | |||
when (iaddr.fire) { | |||
when(iaddr.fire) { | |||
index := index + 1.U | |||
len := len - 1.U | |||
} | |||
} | |||
// deq data | |||
data := odata.deq() | |||
when (odata.fire) { | |||
when(odata.fire) { | |||
state := s_exec | |||
} .elsewhen (imo.idle() === false.B) { | |||
}.elsewhen(imo.idle() === false.B) { | |||
state := s_fetch | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_idle | |||
} | |||
} | |||
} | |||
class EnqAddrDeqMem(mem_io: TraitMemReadIO) extends Module { | |||
class EnqAddrDeqMem(mem_io: MemReadIOTrait) extends Module { | |||
val io = IO(new Bundle { | |||
val iaddr = Flipped(EnqIO(UInt(mem_io.addr.getWidth.W))) | |||
val mem = new MemReadIO(mem_io.mem_depth, mem_io.mem_width) | |||
@@ -211,17 +213,17 @@ class EnqAddrDeqMem(mem_io: TraitMemReadIO) extends Module { | |||
next_token := token | |||
when (token) { | |||
when(token) { | |||
io.odata.enq(io.mem.dout) | |||
when (io.odata.fire()) { | |||
when(io.odata.fire()) { | |||
token := false.B | |||
next_token := false.B | |||
} | |||
} | |||
when (next_token === false.B) { | |||
when(next_token === false.B) { | |||
val addr = io.iaddr.deq() | |||
when (io.iaddr.fire()) { | |||
when(io.iaddr.fire()) { | |||
token := true.B | |||
io.mem.enable() | |||
io.mem.addr := addr |
@@ -14,6 +14,7 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
val io = IO(new Bundle { | |||
val ram = Flipped(new MemIO(ram_io.mem_depth, ram_io.mem_width)) | |||
val buses = MixedVec(ports.map(p => Flipped(new AxiMasterIO(p.addr_width, p.data_width)))) | |||
def bus = buses(0) // shortcut for single bus | |||
}) | |||
@@ -26,18 +27,18 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
io.buses.foreach(bus => bus.sInit()) | |||
when (io.ram.en) { | |||
when (io.ram.we) { | |||
when(io.ram.en) { | |||
when(io.ram.we) { | |||
val data = Wire(Vec(ram_factor, UInt(mem_width.W))) | |||
data := io.ram.din.asTypeOf(data) | |||
for (i <- 0 until ram_factor) { | |||
mem((io.ram.addr << Log2(ram_factor.U)) | i.U) := data(i) | |||
} | |||
} .otherwise { | |||
}.otherwise { | |||
io.ram.dout := Cat((0 until ram_factor).reverse.map(i => | |||
mem((io.ram.addr << Log2(ram_factor.U)) | i.U))) | |||
} | |||
} .otherwise { | |||
}.otherwise { | |||
io.buses.foreach(bus => { | |||
send(bus) | |||
recv(bus) | |||
@@ -54,17 +55,17 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
val addr = Reg(UInt(bus.addr_width.W)) // byte address | |||
val remain = Reg(UInt(bus.addr_width.W)) // remained #transfers | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
val unaligned_addr = bus.read_addr.deq() | |||
when (bus.read_addr.fire) { | |||
//printf("[DramSim] addr=0x%x fire=%d\n", bus.read_addr.bits, bus.read_addr.fire) | |||
when(bus.read_addr.fire) { | |||
//printf("[DramSim] addr=0x%x fire=%d\n", bus.read_addr.bits, bus.read_addr.fire) | |||
state := s_exec | |||
if (bus.data_width == BYTE_WIDTH) { | |||
addr := unaligned_addr | |||
} else { // enforced address alignment | |||
val mask = ~0.U(bus.addr_width.W) << Log2((bus.data_width / BYTE_WIDTH).U) | |||
addr := unaligned_addr & mask | |||
//printf("[DramSim] addr 0x%x := 0x%x & 0x%x\n", (unaligned_addr & mask), unaligned_addr, mask) | |||
//printf("[DramSim] addr 0x%x := 0x%x & 0x%x\n", (unaligned_addr & mask), unaligned_addr, mask) | |||
} | |||
remain := bus.read_addr.getLen() | |||
val size = bus.read_addr.getSize() | |||
@@ -74,17 +75,17 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
bus.read_data.last := (remain === 1.U) | |||
val index = addr / (mem_width / BYTE_WIDTH).U | |||
bus.read_data.enq( | |||
Cat((0 until factor).reverse.map(i => mem(index + i.U))) | |||
) | |||
when (bus.read_data.fire) { | |||
//printf("[DramSim] data=0x%x\n", bus.read_data.bits) | |||
when(bus.read_data.fire) { | |||
//printf("[DramSim] data=0x%x\n", bus.read_data.bits) | |||
addr := addr + (bus.data_width / BYTE_WIDTH).U | |||
remain := remain - 1.U | |||
when (bus.read_data.last.asBool) { | |||
when(bus.read_data.last.asBool) { | |||
state := s_fetch | |||
} | |||
} | |||
@@ -92,7 +93,7 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
} | |||
def recv(bus: AxiMasterIO) { | |||
assert(bus.data_width % mem_width ==0) | |||
assert(bus.data_width % mem_width == 0) | |||
val factor = bus.data_width / mem_width | |||
val bus_size = bus.data_width / BYTE_WIDTH | |||
@@ -105,9 +106,9 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
val strobe = Reg(UInt(bus_size.W)) | |||
val default_strobe = ~0.U(bus_size.W) | |||
when (state === s_fetch) { | |||
when(state === s_fetch) { | |||
val unaligned_addr = bus.write_addr.deq() | |||
when (bus.write_addr.fire) { | |||
when(bus.write_addr.fire) { | |||
state := s_exec | |||
if (bus.data_width == BYTE_WIDTH) { | |||
addr := unaligned_addr | |||
@@ -124,10 +125,10 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
val mem_size = mem_width / BYTE_WIDTH | |||
val data = bus.write_data.deq() | |||
when (bus.write_data.fire) { | |||
when(bus.write_data.fire) { | |||
val index = addr >> log2Ceil(mem_size).U | |||
val strb = strobe & bus.write_data.strb | |||
strobe := default_strobe | |||
@@ -139,7 +140,7 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
mem_word := mem(index + i.U).asTypeOf(mem_word) | |||
bus_word := piece.asTypeOf(bus_word) | |||
(0 until mem_size).foreach(j => { | |||
when (sub_strb(j).asBool) { | |||
when(sub_strb(j).asBool) { | |||
mem_word(j) := bus_word(j) | |||
} | |||
}) | |||
@@ -148,19 +149,18 @@ class DramSimulator(ram_io: MemIO, ports: Seq[AxiMasterIO]) extends Module { | |||
}) | |||
addr := addr + (bus.data_width / BYTE_WIDTH).U | |||
len_count := len_count - 1.U | |||
when (bus.write_data.last.asBool) { | |||
when(bus.write_data.last.asBool) { | |||
state := s_notify | |||
} | |||
} | |||
} | |||
when (state === s_notify) { | |||
when(state === s_notify) { | |||
bus.write_resp.enq(Axi4Config.Resp.OKAY) | |||
when (bus.write_resp.fire) { | |||
when(bus.write_resp.fire) { | |||
state := s_fetch | |||
assert(len_count === 0.U) | |||
} | |||
} | |||
} | |||
} | |||
@@ -2,17 +2,17 @@ package varec.util | |||
import chisel3._ | |||
import chisel3.util._ | |||
import varec.axi4.{Axi4Config, TraitAxiMasterWriteIO, AxiMasterWriteIO} | |||
import varec.axi4.{Axi4Config, AxiMasterWriteIOTrait, AxiMasterWriteIO} | |||
import varec.util.Constants._ | |||
import varec.math.MathForPowerOfTwo._ | |||
/** A bus-writing process model for the EnqBus module. | |||
* | |||
* It wraps up the bus-reading protocol (e.g., AXI4) using the {@@code start} and {@@code run} methods | |||
* and generates an output handle {@@code out} in the valid-ready protocol. | |||
* It wraps up the bus-reading protocol (e.g., AXI4) using the `start` and `run` methods | |||
* and generates an output handle `out` in the valid-ready protocol. | |||
* | |||
* For unaligned writes, assume the {@@code base} has x bytes after an aligned addess, the first x bytes | |||
* in the {@@code in} handle will be dropped, and the strobe for the last transfer should be given. | |||
* For unaligned writes, assume the `base` has x bytes after an aligned address, the first x bytes | |||
* in the `in` handle will be dropped, and the strobe for the last transfer should be given. | |||
*/ | |||
abstract class EnqBusProcess { | |||
/** The input handle in the valid-ready protocol. | |||
@@ -25,8 +25,8 @@ abstract class EnqBusProcess { | |||
/** Start the bus-writing process. | |||
* | |||
* @@param base the base address | |||
* @@param size the bytes to write, where (#bytes == #transfers * bus_size) for aligned writes | |||
* @param base the base address | |||
* @param size the bytes to write, where (#bytes == #transfers * bus_size) for aligned writes | |||
*/ | |||
def start(base: UInt, size: UInt): Unit | |||
@@ -36,7 +36,7 @@ abstract class EnqBusProcess { | |||
} | |||
object EnqBus { | |||
def apply(bus: TraitAxiMasterWriteIO): EnqBusProcess = new EnqBusProcess { | |||
def apply(bus: AxiMasterWriteIOTrait): EnqBusProcess = new EnqBusProcess { | |||
val self = Module(new EnqBus(bus)) | |||
self.io.en := false.B | |||
@@ -56,7 +56,7 @@ object EnqBus { | |||
self.io.start := true.B | |||
self.io.base := base | |||
self.io.size := size | |||
//printf("[EnqBus] base=%x size=%d\n", base, size) | |||
//printf("[EnqBus] base=%x size=%d\n", base, size) | |||
} | |||
def run() { | |||
@@ -73,7 +73,7 @@ object EnqBus { | |||
class EnqBus(addr_width: Int, data_width: Int) extends Module { | |||
val data_size = data_width / BYTE_WIDTH | |||
def this(bus_io: TraitAxiMasterWriteIO) { | |||
def this(bus_io: AxiMasterWriteIOTrait) { | |||
this(bus_io.write_addr.bits.getWidth, bus_io.write_data.bits.getWidth) | |||
} | |||
@@ -105,8 +105,8 @@ class EnqBus(addr_width: Int, data_width: Int) extends Module { | |||
io.idle := (state === s_idle) | |||
when (io.en) { | |||
when (io.idle && io.start) { | |||
when(io.en) { | |||
when(io.idle && io.start) { | |||
state := s_fetch | |||
addr := io.base | |||
@@ -125,65 +125,65 @@ class EnqBus(addr_width: Int, data_width: Int) extends Module { | |||
len_count := (total_size #/ data_size) + has_last_partial | |||
first_strobe := default_strobe << prepended_size | |||
when (has_last_partial) { | |||
when(has_last_partial) { | |||
last_strobe := ~(default_strobe << last_partial_size) | |||
} | |||
} | |||
} | |||
when (state === s_fetch) { | |||
when (len_count > 0.U) { | |||
when(state === s_fetch) { | |||
when(len_count > 0.U) { | |||
val len = len_count.min(burst_max) | |||
io.bus.write_addr.setLen(len) | |||
io.bus.write_addr.setSize(data_size) | |||
io.bus.write_addr.enq(addr) | |||
when (io.bus.write_addr.fire) { | |||
//printf("[EnqBus] addr 0x%x fire curr_len=%d tot_len=%d\n", io.bus.write_addr.bits, len, len_count) | |||
when(io.bus.write_addr.fire) { | |||
//printf("[EnqBus] addr 0x%x fire curr_len=%d tot_len=%d\n", io.bus.write_addr.bits, len, len_count) | |||
state := s_exec | |||
addr := addr + (len #* data_size) | |||
len_count := len_count - len | |||
burst_count := len | |||
} | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_idle | |||
} | |||
} | |||
when (state === s_exec) { | |||
when(state === s_exec) { | |||
connect() | |||
val next_burst_count = burst_count - 1.U | |||
val is_last = WireDefault(false.B) | |||
when (next_burst_count === 0.U) { | |||
when(next_burst_count === 0.U) { | |||
io.bus.write_data.last := true.B | |||
when (len_count === 0.U) { | |||
when(len_count === 0.U) { | |||
is_last := true.B | |||
} | |||
} | |||
when (is_first && is_last) { | |||
when(is_first && is_last) { | |||
io.bus.write_data.strb := first_strobe & last_strobe | |||
} .elsewhen (is_first) { | |||
}.elsewhen(is_first) { | |||
io.bus.write_data.strb := first_strobe | |||
} .elsewhen (is_last) { | |||
}.elsewhen(is_last) { | |||
io.bus.write_data.strb := last_strobe | |||
} | |||
when (io.bus.write_data.fire) { | |||
//printf("[EnqBus] strobe 0x%x\n", io.bus.write_data.strb) | |||
//printf("[EnqBus] data fire 0x%x\n", io.bus.write_data.bits) | |||
when(io.bus.write_data.fire) { | |||
//printf("[EnqBus] strobe 0x%x\n", io.bus.write_data.strb) | |||
//printf("[EnqBus] data fire 0x%x\n", io.bus.write_data.bits) | |||
is_first := false.B | |||
burst_count := next_burst_count | |||
when (next_burst_count === 0.U) { | |||
when(next_burst_count === 0.U) { | |||
state := s_wait | |||
} | |||
} | |||
} | |||
when (state === s_wait) { | |||
when(state === s_wait) { | |||
val resp = io.bus.write_resp.deq() | |||
when (io.bus.write_resp.fire) { | |||
//printf("[EnqBus] write_resp fire len_count=%d\n", len_count) | |||
when (len_count === 0.U) { | |||
when(io.bus.write_resp.fire) { | |||
//printf("[EnqBus] write_resp fire len_count=%d\n", len_count) | |||
when(len_count === 0.U) { | |||
state := s_idle | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_fetch | |||
} | |||
assert(burst_count === 0.U) |
@@ -5,8 +5,8 @@ import chisel3.util._ | |||
/** A memory-writing process model for the EnqMem module. | |||
* | |||
* It accepts the input data from the handle {@code in} in the valid-ready protocol | |||
* and generates the control signals for on-chip memory using the {@code start} and {@code run} methods. | |||
* It accepts the input data from the handle `in` in the valid-ready protocol | |||
* and generates the control signals for on-chip memory using the `start` and `run` methods. | |||
*/ | |||
abstract class EnqMemProcess { | |||
/** The input handle in the valid-ready protocol. | |||
@@ -20,7 +20,7 @@ abstract class EnqMemProcess { | |||
/** Start the memory-writing process. | |||
* | |||
* @param base the base address | |||
* @param len the number of transfers, where #bytes == len * mem.din.getWidth/8 | |||
* @param len the number of transfers, where #bytes == len * mem.din.getWidth/8 | |||
* @param drop drops a few data at the beginning | |||
*/ | |||
def start(base: UInt, len: UInt, drop: UInt = 0.U): Unit | |||
@@ -31,7 +31,7 @@ abstract class EnqMemProcess { | |||
} | |||
object EnqMem { | |||
def apply(mem: TraitMemWriteIO): EnqMemProcess = new EnqMemProcess { | |||
def apply(mem: MemWriteIOTrait): EnqMemProcess = new EnqMemProcess { | |||
val self = Module(new EnqMem(mem)) | |||
self.io.en := false.B | |||
@@ -68,7 +68,7 @@ object EnqMem { | |||
} | |||
} | |||
class EnqMem(mem_io: TraitMemWriteIO) extends Module { | |||
class EnqMem(mem_io: MemWriteIOTrait) extends Module { | |||
val mem_depth = mem_io.mem_depth | |||
val data_width = mem_io.din.getWidth | |||
val addr_width = mem_io.addr.getWidth | |||
@@ -98,38 +98,38 @@ class EnqMem(mem_io: TraitMemWriteIO) extends Module { | |||
io.idle := (state === s_idle) | |||
when (io.en) { | |||
when (io.idle && io.start) { | |||
when (io.drop === 0.U) { | |||
when(io.en) { | |||
when(io.idle && io.start) { | |||
when(io.drop === 0.U) { | |||
state := s_fetch | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_wait | |||
} | |||
index := io.base | |||
len := io.len | |||
drop := io.drop | |||
//printf("[EnqMem] start index=0x%x len=%d drop=%d\n", io.base, io.len, io.drop) | |||
//printf("[EnqMem] start index=0x%x len=%d drop=%d\n", io.base, io.len, io.drop) | |||
} | |||
when (state === s_wait) { | |||
when (drop === 0.U) { | |||
when(state === s_wait) { | |||
when(drop === 0.U) { | |||
state := s_fetch | |||
} .otherwise { | |||
}.otherwise { | |||
data := io.in.deq() | |||
when (io.in.fire()) { | |||
when(io.in.fire()) { | |||
drop := drop - 1.U | |||
//printf("[EnqMem] drop %d => %d\n", drop, drop - 1.U) | |||
//printf("[EnqMem] drop %d => %d\n", drop, drop - 1.U) | |||
} | |||
} | |||
} | |||
when (state === s_fetch) { | |||
//printf("[EnqMem] s_fetch index=0x%x len=%d\n", index, len) | |||
when(state === s_fetch) { | |||
//printf("[EnqMem] s_fetch index=0x%x len=%d\n", index, len) | |||
pullData() | |||
} | |||
when (state === s_exec) { | |||
//printf("[EnqMem] s_exec mem[0x%x] = 0x%x\n", index, data) | |||
when(state === s_exec) { | |||
//printf("[EnqMem] s_exec mem[0x%x] = 0x%x\n", index, data) | |||
io.mem.enable() | |||
io.mem.addr := index | |||
io.mem.din := data | |||
@@ -138,14 +138,14 @@ class EnqMem(mem_io: TraitMemWriteIO) extends Module { | |||
} | |||
def pullData() { | |||
when (len === 0.U) { | |||
when(len === 0.U) { | |||
state := s_idle | |||
} .otherwise { | |||
}.otherwise { | |||
data := io.in.deq() | |||
when (io.in.fire()) { | |||
when(io.in.fire()) { | |||
state := s_exec | |||
len := len - 1.U | |||
} .otherwise { | |||
}.otherwise { | |||
state := s_fetch | |||
} | |||
} |
@@ -3,26 +3,29 @@ package varec.util | |||
import chisel3._ | |||
import chisel3.util._ | |||
trait TraitMemIO extends TraitMemWriteIO with TraitMemReadIO { | |||
trait MemIOTrait extends MemWriteIOTrait with MemReadIOTrait { | |||
override def enable() { | |||
super[TraitMemWriteIO].disable() | |||
super[TraitMemReadIO].enable() | |||
super[MemWriteIOTrait].disable() | |||
super[MemReadIOTrait].enable() | |||
} | |||
def wenable() { | |||
super[TraitMemReadIO].disable() | |||
super[TraitMemWriteIO].enable() | |||
super[MemReadIOTrait].disable() | |||
super[MemWriteIOTrait].enable() | |||
} | |||
override def disable() { | |||
super[TraitMemReadIO].disable() | |||
super[TraitMemWriteIO].disable() | |||
super[MemReadIOTrait].disable() | |||
super[MemWriteIOTrait].disable() | |||
} | |||
override def <>(that: TraitMemIO) { | |||
super[TraitMemReadIO].<>(that) | |||
super[TraitMemWriteIO].<>(that) | |||
override def <>(that: MemIOTrait) { | |||
super[MemReadIOTrait].<>(that) | |||
super[MemWriteIOTrait].<>(that) | |||
} | |||
} | |||
trait TraitMemReadIO extends Bundle { | |||
trait MemReadIOTrait extends Bundle { | |||
val mem_depth: Int | |||
val mem_width: Int | |||
@@ -33,24 +36,26 @@ trait TraitMemReadIO extends Bundle { | |||
def enable() { | |||
en := true.B | |||
} | |||
def disable() { | |||
en := false.B | |||
addr := DontCare | |||
} | |||
def <>(that: TraitMemIO) { | |||
def <>(that: MemIOTrait) { | |||
this.en <> that.en | |||
this.addr <> that.addr | |||
this.dout <> that.dout | |||
} | |||
def <>(that: TraitMemReadIO) { | |||
def <>(that: MemReadIOTrait) { | |||
this.en <> that.en | |||
this.addr <> that.addr | |||
this.dout <> that.dout | |||
} | |||
} | |||
trait TraitMemWriteIO extends Bundle { | |||
trait MemWriteIOTrait extends Bundle { | |||
val mem_depth: Int | |||
val mem_width: Int | |||
@@ -63,24 +68,27 @@ trait TraitMemWriteIO extends Bundle { | |||
en := true.B | |||
we := true.B | |||
} | |||
def disable() { | |||
en := false.B | |||
we := false.B | |||
addr := DontCare | |||
din := DontCare | |||
} | |||
def write(addr: UInt, data: UInt) { | |||
this.addr := addr | |||
this.din := data | |||
} | |||
def <>(that: TraitMemIO) { | |||
def <>(that: MemIOTrait) { | |||
this.en <> that.en | |||
this.we <> that.we | |||
this.addr <> that.addr | |||
this.din <> that.din | |||
} | |||
def <>(that: TraitMemWriteIO) { | |||
def <>(that: MemWriteIOTrait) { | |||
this.en <> that.en | |||
this.we <> that.we | |||
this.addr <> that.addr | |||
@@ -89,7 +97,7 @@ trait TraitMemWriteIO extends Bundle { | |||
} | |||
class MemReadIO(val mem_depth: Int, val mem_width: Int) extends TraitMemReadIO { | |||
class MemReadIO(val mem_depth: Int, val mem_width: Int) extends MemReadIOTrait { | |||
val en = Output(Bool()) | |||
val addr = Output(UInt(log2Ceil(mem_depth).W)) | |||
val dout = Input(UInt(mem_width.W)) | |||
@@ -97,7 +105,7 @@ class MemReadIO(val mem_depth: Int, val mem_width: Int) extends TraitMemReadIO { | |||
override def cloneType: this.type = new MemReadIO(mem_depth, mem_width).asInstanceOf[this.type] | |||
} | |||
class MemWriteIO(val mem_depth: Int, val mem_width: Int) extends TraitMemWriteIO { | |||
class MemWriteIO(val mem_depth: Int, val mem_width: Int) extends MemWriteIOTrait { | |||
val en = Output(Bool()) | |||
val we = Output(Bool()) | |||
val addr = Output(UInt(log2Ceil(mem_depth).W)) | |||
@@ -106,7 +114,7 @@ class MemWriteIO(val mem_depth: Int, val mem_width: Int) extends TraitMemWriteIO | |||
override def cloneType: this.type = new MemWriteIO(mem_depth, mem_width).asInstanceOf[this.type] | |||
} | |||
class MemIO(val mem_depth: Int, val mem_width: Int) extends TraitMemIO { | |||
class MemIO(val mem_depth: Int, val mem_width: Int) extends MemIOTrait { | |||
val en = Output(Bool()) | |||
val we = Output(Bool()) | |||
val addr = Output(UInt(log2Ceil(mem_depth).W)) | |||
@@ -117,54 +125,7 @@ class MemIO(val mem_depth: Int, val mem_width: Int) extends TraitMemIO { | |||
} | |||
// exclusive read or write | |||
@deprecated("use SinglePortSram instead", "commit f5a2e57") | |||
class SinglePortMem(WIDTH: Int, DEPTH: Int) extends Module { | |||
val io = IO( | |||
Flipped(new MemIO(DEPTH, WIDTH)) | |||
) | |||
//val mem = SyncReadMem(DEPTH, UInt(WIDTH.W)) | |||
val mem = Mem(DEPTH, UInt(WIDTH.W)) | |||
when (io.en) { | |||
when (io.we) { | |||
mem.write(io.addr, io.din) | |||
io.dout := DontCare | |||
//io.dout_valid := false.B | |||
} .otherwise { | |||
io.dout := mem.read(io.addr) | |||
//io.dout_valid := true.B | |||
} | |||
} .otherwise { | |||
io.dout := DontCare | |||
//io.dout_valid := false.B | |||
} | |||
} | |||
// write port A + read port B | |||
@deprecated("use SimpleDualPortSram instead", "commit f5a2e57") | |||
class SimpleDualPortMem(WIDTH: Int, DEPTH: Int) extends Module { | |||
val io = IO(new Bundle { | |||
val a = Flipped(new MemWriteIO(DEPTH, WIDTH)) | |||
val b = Flipped(new MemReadIO(DEPTH, WIDTH)) | |||
}) | |||
//val mem = SyncReadMem(DEPTH, UInt(WIDTH.W)) | |||
val mem = Mem(DEPTH, UInt(WIDTH.W)) | |||
when (io.a.en && io.a.we) { | |||
mem.write(io.a.addr, io.a.din) | |||
} | |||
when (io.b.en) { | |||
io.b.dout := mem.read(io.b.addr) | |||
} .otherwise { | |||
io.b.dout := DontCare | |||
} | |||
} | |||
// exclusive read or write | |||
class SinglePortSram(mem_depth: Int, mem_width: Int) extends Module { | |||
class SinglePortMem(mem_depth: Int, mem_width: Int) extends Module { | |||
val io = IO( | |||
Flipped(new MemIO(mem_depth, mem_width)) | |||
) | |||
@@ -174,10 +135,10 @@ class SinglePortSram(mem_depth: Int, mem_width: Int) extends Module { | |||
io.dout := dout | |||
when (io.en) { | |||
when (io.we) { | |||
when(io.en) { | |||
when(io.we) { | |||
mem.write(io.addr, io.din) | |||
} .otherwise { | |||
}.otherwise { | |||
dout := mem.read(io.addr) // buffered; io.dout available in next cycle | |||
} | |||
} | |||
@@ -186,7 +147,7 @@ class SinglePortSram(mem_depth: Int, mem_width: Int) extends Module { | |||
} | |||
// write port A + read port B | |||
class SimpleDualPortSram(mem_depth: Int, mem_width: Int) extends Module { | |||
class SimpleDualPortMem(mem_depth: Int, mem_width: Int) extends Module { | |||
val io = IO(new Bundle { | |||
val a = Flipped(new MemWriteIO(mem_depth, mem_width)) | |||
val b = Flipped(new MemReadIO(mem_depth, mem_width)) | |||
@@ -197,11 +158,11 @@ class SimpleDualPortSram(mem_depth: Int, mem_width: Int) extends Module { | |||
io.b.dout := dout | |||
when (io.a.en && io.a.we) { | |||
when(io.a.en && io.a.we) { | |||
mem.write(io.a.addr, io.a.din) | |||
} | |||
when (io.b.en) { | |||
when(io.b.en) { | |||
dout := mem.read(io.b.addr) // buffered; io.b.dout available in next cycle | |||
} | |||
} |
@@ -15,7 +15,7 @@ class EnqBusWrapper(val addr_width: Int, val data_width: Int) extends Module { | |||
val start = Input(Bool()) | |||
val idle = Output(Bool()) | |||
val ram = Flipped(new MemIO(math.pow(2,addr_width).toInt, data_width)) | |||
val ram = Flipped(new MemIO(math.pow(2, addr_width).toInt, data_width)) | |||
}) | |||
val enq_bus = Module(new EnqBus(new AxiMasterWriteIO(addr_width, data_width))) | |||
@@ -34,15 +34,19 @@ class EnqBusWrapper(val addr_width: Int, val data_width: Int) extends Module { | |||
sim.io.ram <> io.ram | |||
} | |||
class EnqBusUnitTester(c: EnqBusWrapper) extends PeekPokeTester(c) { | |||
val base = 1024 | |||
assert(c.io.ram.dout.getWidth == 32) | |||
assert(base % (c.io.ram.dout.getWidth / BYTE_WIDTH) == 0) | |||
val len = 600 | |||
val pattern = Array(BigInt("cccccccc",16), BigInt("deadbeef",16), BigInt("cdcdcdcd",16)) | |||
val pattern = Array(BigInt("cccccccc", 16), BigInt("deadbeef", 16), BigInt("cdcdcdcd", 16)) | |||
//val pattern_out = Array(BigInt("efcccccc",16), BigInt("cddeadbe",16), BigInt("cccdcdcd",16)) | |||
def pattern_out = pattern | |||
val data = (0 until len).map(i => pattern(i % pattern.length)) | |||
//val data_out = List(BigInt("ccffffff",16)) ++ (0 until len).map(i => pattern_out(i % pattern_out.length)) | |||
def data_out = data | |||
@@ -68,7 +72,7 @@ class EnqBusUnitTester(c: EnqBusWrapper) extends PeekPokeTester(c) { | |||
for (i <- 0 until data_out.length) { | |||
val addr = base / (c.io.ram.dout.getWidth / 8) | |||
poke(c.io.ram.addr, addr+i) | |||
poke(c.io.ram.addr, addr + i) | |||
expect(c.io.ram.dout, data_out(i)) | |||
} | |||
} | |||
@@ -85,7 +89,7 @@ class DeqMemEnqBusWrapper(mem_width: Int, mem_depth: Int, ram_width: Int, ram_de | |||
val idle = Output(Bool()) | |||
}) | |||