凿子 AlreadyBoundException

Chisel AlreadyBoundException

我正在基于 Sodor 暂存存储器为 SoC 开发一个简单的片上存储器。因此,首先我将该设计的一个稍微修改过的版本转换为 chisel 3。现在,我收到了关于我无法理解的有界类型的异常。

[info] - should correctly write and read data *** FAILED ***
[info]   chisel3.core.Binding$BindingException: Error: Cannot set as output .M_WR: Already bound to LitBinding()
[info]   at chisel3.core.Binding$.bind(Binding.scala:100)
[info]   at chisel3.core.Output$.apply(Data.scala:50)
[info]   at chisel3.util.ReadyValidIO.<init>(Decoupled.scala:22)
[info]   at chisel3.util.DecoupledIO.<init>(Decoupled.scala:72)
[info]   at chisel3.util.Decoupled$.apply(Decoupled.scala:81)
[info]   at mem.MemPortIO.<init>(memory.scala:40)
[info]   at mem.OnChipMemory$$anon.<init>(memory.scala:49)
[info]   at mem.OnChipMemory.<init>(memory.scala:47)
[info]   at mem.memoryTester$$anonfun$$anonfun$apply$$anonfun$apply$mcV$sp.apply(memoryTest.scala:33)
[info]   at mem.memoryTester$$anonfun$$anonfun$apply$$anonfun$apply$mcV$sp.apply(memoryTest.scala:33)
[info]   at chisel3.core.Module$.do_apply(Module.scala:35)
[info]   at chisel3.Driver$$anonfun$elaborate.apply(Driver.scala:194)
[info]   at chisel3.Driver$$anonfun$elaborate.apply(Driver.scala:194)
[info]   at chisel3.internal.Builder$$anonfun$build.apply(Builder.scala:206)
[info]   at chisel3.internal.Builder$$anonfun$build.apply(Builder.scala:204)
[info]   at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
[info]   at chisel3.internal.Builder$.build(Builder.scala:204)
[info]   at chisel3.Driver$.elaborate(Driver.scala:194)
[info]   at chisel3.Driver$.execute(Driver.scala:229)
[info]   at chisel3.iotesters.setupFirrtlTerpBackend$.apply(FirrtlTerpBackend.scala:110)
[info]   at chisel3.iotesters.Driver$.execute(Driver.scala:47)
[info]   at chisel3.iotesters.Driver$.apply(Driver.scala:210)
[info]   at mem.memoryTester$$anonfun$$anonfun$apply.apply$mcV$sp(memoryTest.scala:33)
[info]   at mem.memoryTester$$anonfun$$anonfun$apply.apply(memoryTest.scala:33)
[info]   at mem.memoryTester$$anonfun$$anonfun$apply.apply(memoryTest.scala:33)
[info]   at org.scalatest.Transformer$$anonfun$apply.apply$mcV$sp(Transformer.scala:22)
[info]   at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
[info]   at org.scalatest.FlatSpecLike$$anon.apply(FlatSpecLike.scala:1647)
[info]   at org.scalatest.Suite$class.withFixture(Suite.scala:1122)
[info]   at org.scalatest.FlatSpec.withFixture(FlatSpec.scala:1683)
[info]   at org.scalatest.FlatSpecLike$class.invokeWithFixture(FlatSpecLike.scala:1644)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTest.apply(FlatSpecLike.scala:1656)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTest.apply(FlatSpecLike.scala:1656)
[info]   at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
[info]   at org.scalatest.FlatSpecLike$class.runTest(FlatSpecLike.scala:1656)
[info]   at org.scalatest.FlatSpec.runTest(FlatSpec.scala:1683)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTests.apply(FlatSpecLike.scala:1714)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTests.apply(FlatSpecLike.scala:1714)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes.apply(Engine.scala:413)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes.apply(Engine.scala:401)
[info]   at scala.collection.immutable.List.foreach(List.scala:381)
[info]   at org.scalatest.SuperEngine.traverseSubNodes(Engine.scala:401)
[info]   at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:390)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes.apply(Engine.scala:427)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes.apply(Engine.scala:401)
[info]   at scala.collection.immutable.List.foreach(List.scala:381)
[info]   at org.scalatest.SuperEngine.traverseSubNodes(Engine.scala:401)
[info]   at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:396)
[info]   at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:483)
[info]   at org.scalatest.FlatSpecLike$class.runTests(FlatSpecLike.scala:1714)
[info]   at org.scalatest.FlatSpec.runTests(FlatSpec.scala:1683)
[info]   at org.scalatest.Suite$class.run(Suite.scala:1424)
[info]   at org.scalatest.FlatSpec.org$scalatest$FlatSpecLike$$super$run(FlatSpec.scala:1683)
[info]   at org.scalatest.FlatSpecLike$$anonfun$run.apply(FlatSpecLike.scala:1760)
[info]   at org.scalatest.FlatSpecLike$$anonfun$run.apply(FlatSpecLike.scala:1760)
[info]   at org.scalatest.SuperEngine.runImpl(Engine.scala:545)
[info]   at org.scalatest.FlatSpecLike$class.run(FlatSpecLike.scala:1760)
[info]   at org.scalatest.FlatSpec.run(FlatSpec.scala:1683)
[info]   at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:466)
[info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:677)
[info]   at sbt.TestRunner.runTest(TestFramework.scala:76)
[info]   at sbt.TestRunner.run(TestFramework.scala:85)
[info]   at sbt.TestFramework$$anon$$anonfun$$init$$$anonfun$apply.apply(TestFramework.scala:202)
[info]   at sbt.TestFramework$$anon$$anonfun$$init$$$anonfun$apply.apply(TestFramework.scala:202)
[info]   at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:185)
[info]   at sbt.TestFramework$$anon$$anonfun$$init$.apply(TestFramework.scala:202)
[info]   at sbt.TestFramework$$anon$$anonfun$$init$.apply(TestFramework.scala:202)
[info]   at sbt.TestFunction.apply(TestFramework.scala:207)
[info]   at sbt.Tests$$anonfun.apply(Tests.scala:216)
[info]   at sbt.Tests$$anonfun.apply(Tests.scala:216)
[info]   at sbt.std.Transform$$anon$$anonfun$apply.apply(System.scala:44)
[info]   at sbt.std.Transform$$anon$$anonfun$apply.apply(System.scala:44)
[info]   at sbt.std.Transform$$anon.work(System.scala:63)
[info]   at sbt.Execute$$anonfun$submit$$anonfun$apply.apply(Execute.scala:228)
[info]   at sbt.Execute$$anonfun$submit$$anonfun$apply.apply(Execute.scala:228)
[info]   at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
[info]   at sbt.Execute.work(Execute.scala:237)
[info]   at sbt.Execute$$anonfun$submit.apply(Execute.scala:228)
[info]   at sbt.Execute$$anonfun$submit.apply(Execute.scala:228)
[info]   at sbt.ConcurrentRestrictions$$anon$$anonfun.apply(ConcurrentRestrictions.scala:159)
[info]   at sbt.CompletionService$$anon.call(CompletionService.scala:28)
[info]   at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info]   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[info]   at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info]   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[info]   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[info]   at java.lang.Thread.run(Thread.java:745)
[info] ScalaCheck
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] ScalaTest

我不清楚导致问题的值。首先,我认为这是我在 Mem 和 IO 端口中使用的 Vec 的问题(因为我发现了一个类似异常的解释)。但是即使在我摆脱它们之后问题仍然存在。我什至尝试摆脱克隆功能。

现在,我对问题的原因一无所知。我发布了内存的源代码的主要部分(除了参数声明和一些简单的函数)以防它可能有用。

trait MemOpConstants 

{
    val MT_X  = Bits(0, 3)  // memory transfer type
    val MT_B  = Bits(1, 3)
    val MT_H  = Bits(2, 3)
    val MT_W  = Bits(3, 3)
    val MT_D  = Bits(4, 3)
    val MT_BU = Bits(5, 3)
    val MT_HU = Bits(6, 3)
    val MT_WU = Bits(7, 3)

    val M_X   = Bits("b0", 1)   // access type
    val M_RD  = Bits("b0", 1)   // load
    val M_WR  = Bits("b1", 1)   // store
}

class MemReq(data_width: Int)(implicit config: Configuration) extends Bundle with MemOpConstants
{
    val addr = UInt(width = config.xprlen)
    val data = Bits(width = data_width)
    val fcn  = Bits(width = M_X.getWidth)  // memory function code
    val typ  = Bits(width = MT_X.getWidth) // memory access type
    override def cloneType = { new MemReq(data_width).asInstanceOf[this.type] }
}

class MemResp(data_width: Int) extends Bundle
{
    val data = Bits(width = data_width)
    override def cloneType = { new MemResp(data_width).asInstanceOf[this.type] }
}

class MemPortIO(data_width: Int)(implicit config: Configuration) extends Bundle     // constructor for IO interface of data memory
{
    val req    = Decoupled(new MemReq(data_width))                  // ready valid pair
    val resp   = (new ValidIO(new MemResp(data_width))).flip            // valid signal
    override def cloneType = { new MemPortIO(data_width).asInstanceOf[this.type] }
}

class OnChipMemory(num_ports: Int = 2, num_bytes: Int = (1 << 15), seq_read: Boolean = false)(implicit config: Configuration) extends Module with MemOpConstants
{
    val io = IO(new Bundle{
        val port = Vec(num_ports, (new MemPortIO(data_width = config.xprlen)).flip) 
    })

val num_bytes_per_line = 4
val num_lines = num_bytes/num_bytes_per_line

val lsb_idx = log2Up(num_bytes_per_line)    // index of lsb in address

val chipMem = Mem(Vec(4, UInt(width = 32)), num_lines)  // memory

for (i <- 0 until num_ports)
{
    io.port(i).resp.valid := Reg(next = io.port(i).req.valid)

    io.port(i).req.ready := Bool(true) // for now

    val req_valid      = io.port(i).req.valid
    val req_addr       = io.port(i).req.bits.addr
    val req_data       = io.port(i).req.bits.data
    val req_fn         = io.port(i).req.bits.fcn
    val req_typ        = io.port(i).req.bits.typ
    val byte_shift_amt = io.port(i).req.bits.addr(1,0)
    val bit_shift_amt  = Cat(byte_shift_amt, UInt(0,3))

    //mem read
    val r_data_idx = Reg(UInt())

    val data_idx = req_addr >> UInt(lsb_idx)
    val read_data = Bits()
    val rdata = Bits()

    if (seq_read)
    {
         read_data := chipMem(r_data_idx)
         rdata     := LoadDataGen((read_data >> Reg(next=bit_shift_amt)), Reg(next=req_typ))
    }
    else
    {
         read_data := chipMem(data_idx)
         rdata     := LoadDataGen((read_data >> bit_shift_amt), req_typ)
    }

    io.port(i).resp.bits.data := rdata

    //mem write
    when (req_valid && req_fn === M_WR)
    {
         val wdata = StoreDataGen(req_data, req_typ) 
         val wmask = ((StoreMask(req_typ) << bit_shift_amt)(31,0)).toBools

         chipMem.write(data_idx, wdata, wmask)
    }
    .elsewhen (req_valid && req_fn === M_RD)
    {
         r_data_idx := data_idx
    }
}
}

object StoreDataGen extends MemOpConstants
{
    def apply(din: Bits, typ: Bits): Vec[UInt] =
    {
        val word    =   (typ.equals(MT_W)) || (typ.equals(MT_WU))
        val half    =   (typ.equals(MT_H)) || (typ.equals(MT_HU))
        val byte    =   (typ.equals(MT_B)) || (typ.equals(MT_BU))

        val dout    =   Mux(Bool(byte), Vec(4, din( 7,0)),
                Mux(Bool(half), Vec(din(15,8), din( 7,0), din(15,8), din( 7,0)),
                        Vec(din(31,25), din(24,16), din(15,8), din( 7,0))))
        return dout
    }
}

拥有更多带有行号的代码会有所帮助,但根据特征 MemOpConstants 的名称,我猜它包含一些 Chisel 文字。编译器抱怨它不能从 MemPortIO 中创建一个 IO 端口,因为它包含一个包含文字作为元素的 Bundle MemReq。

IO 端口只能包含纯的、未绑定的 Chisel 数据类型,而不是文字、Reg、Mem 或 Wire。

如果你想让这些常量在 IO 端口可用,你应该定义插槽 (UInts) 来接收它们,然后将这些插槽连接到实际的 constant/literal 值。不要将常量本身放在 IO 端口定义中。

您在 MemOpConstants 中的所有定义都是位类型的文字(常量)。它们具有值和宽度。这些值使它们成为文字(常量),不适合包含在 IO 端口定义中。