Browse Source

Reorganize file locations

master^2
Guojie Luo 2 years ago
parent
commit
77f6b02e67
16 changed files with 424 additions and 499 deletions
  1. +2
    -2
      scalastyle-config.xml
  2. +92
    -56
      src/main/scala/varec/axi4/Axi.scala
  3. +8
    -6
      src/main/scala/varec/math/MathForPowerOfTwo.scala
  4. +19
    -17
      src/main/scala/varec/shell/XclControl.scala
  5. +27
    -25
      src/main/scala/varec/util/Bus.scala
  6. +26
    -23
      src/main/scala/varec/util/BusHelper.scala
  7. +16
    -12
      src/main/scala/varec/util/Channel.scala
  8. +0
    -0
      src/main/scala/varec/util/Constants.scala
  9. +17
    -17
      src/main/scala/varec/util/DeqBus.scala
  10. +32
    -30
      src/main/scala/varec/util/DeqMem.scala
  11. +22
    -22
      src/main/scala/varec/util/DramSimulator.scala
  12. +33
    -33
      src/main/scala/varec/util/EnqBus.scala
  13. +23
    -23
      src/main/scala/varec/util/EnqMem.scala
  14. +34
    -73
      src/main/scala/varec/util/Mem.scala
  15. +29
    -21
      src/test/scala/varec/util/BusTest.scala
  16. +44
    -139
      src/test/scala/varec/util/MemTest.scala

+ 2
- 2
scalastyle-config.xml View File

@@ -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>


src/main/scala/axi4/Axi.scala → src/main/scala/varec/axi4/Axi.scala View File

@@ -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]
}


src/main/scala/math/MathForPowerOfTwo.scala → src/main/scala/varec/math/MathForPowerOfTwo.scala View File

@@ -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
}
}

}

src/main/scala/shell/XclControl.scala → src/main/scala/varec/shell/XclControl.scala View File

@@ -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
}
}

src/main/scala/util/Bus.scala → src/main/scala/varec/util/Bus.scala View File

@@ -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() {
//

src/main/scala/util/BusHelper.scala → src/main/scala/varec/util/BusHelper.scala View File

@@ -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) {
}
}


src/main/scala/util/Channel.scala → src/main/scala/varec/util/Channel.scala View File

@@ -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
}

src/main/scala/util/Constants.scala → src/main/scala/varec/util/Constants.scala View File


src/main/scala/util/DeqBus.scala → src/main/scala/varec/util/DeqBus.scala View File

@@ -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)
}

src/main/scala/util/DeqMem.scala → src/main/scala/varec/util/DeqMem.scala View File

@@ -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

src/main/scala/util/DramSimulator.scala → src/main/scala/varec/util/DramSimulator.scala View File

@@ -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)
}
}
}
}


src/main/scala/util/EnqBus.scala → src/main/scala/varec/util/EnqBus.scala View File

@@ -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)

src/main/scala/util/EnqMem.scala → src/main/scala/varec/util/EnqMem.scala View File

@@ -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
}
}

src/main/scala/util/Mem.scala → src/main/scala/varec/util/Mem.scala View File

@@ -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
}
}

src/test/scala/util/BusTest.scala → src/test/scala/varec/util/BusTest.scala View File

@@ -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())
})