0
votes

I am developing a simple on chip memory for an SoC, based on Sodor scratchpad memory. So, first I'm converting a slightly modified version of that design to chisel 3. Now, I'm getting this exception regarding a bounded type that I can't understand.

[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$1.<init>(memory.scala:49)
[info]   at mem.OnChipMemory.<init>(memory.scala:47)
[info]   at mem.memoryTester$$anonfun$3$$anonfun$apply$1$$anonfun$apply$mcV$sp$1.apply(memoryTest.scala:33)
[info]   at mem.memoryTester$$anonfun$3$$anonfun$apply$1$$anonfun$apply$mcV$sp$1.apply(memoryTest.scala:33)
[info]   at chisel3.core.Module$.do_apply(Module.scala:35)
[info]   at chisel3.Driver$$anonfun$elaborate$1.apply(Driver.scala:194)
[info]   at chisel3.Driver$$anonfun$elaborate$1.apply(Driver.scala:194)
[info]   at chisel3.internal.Builder$$anonfun$build$1.apply(Builder.scala:206)
[info]   at chisel3.internal.Builder$$anonfun$build$1.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$3$$anonfun$apply$1.apply$mcV$sp(memoryTest.scala:33)
[info]   at mem.memoryTester$$anonfun$3$$anonfun$apply$1.apply(memoryTest.scala:33)
[info]   at mem.memoryTester$$anonfun$3$$anonfun$apply$1.apply(memoryTest.scala:33)
[info]   at org.scalatest.Transformer$$anonfun$apply$1.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$1.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$1(FlatSpecLike.scala:1644)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTest$1.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$1.apply(FlatSpecLike.scala:1714)
[info]   at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:413)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
[info]   at scala.collection.immutable.List.foreach(List.scala:381)
[info]   at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
[info]   at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:390)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:427)
[info]   at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
[info]   at scala.collection.immutable.List.foreach(List.scala:381)
[info]   at org.scalatest.SuperEngine.traverseSubNodes$1(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$1.apply(FlatSpecLike.scala:1760)
[info]   at org.scalatest.FlatSpecLike$$anonfun$run$1.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$1(TestFramework.scala:76)
[info]   at sbt.TestRunner.run(TestFramework.scala:85)
[info]   at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
[info]   at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
[info]   at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:185)
[info]   at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
[info]   at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
[info]   at sbt.TestFunction.apply(TestFramework.scala:207)
[info]   at sbt.Tests$$anonfun$9.apply(Tests.scala:216)
[info]   at sbt.Tests$$anonfun$9.apply(Tests.scala:216)
[info]   at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
[info]   at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
[info]   at sbt.std.Transform$$anon$4.work(System.scala:63)
[info]   at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
[info]   at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.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$1.apply(Execute.scala:228)
[info]   at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
[info]   at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
[info]   at sbt.CompletionService$$anon$2.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

I'm not clear about the value that is causing the problem. First I thought it was a problem with the Vec's I use in the Mem and IO ports (because of an explanation I found for a similar exception). But the problem exists even after I get rid of them. I even tried getting rid of clone functions.

Now, I'm clueless about the cause of the problem. I'm posting the main section of the source code (except parameter declarations and few simple functions) for the memory in case it might be useful.

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
    }
}
2
It appears that the stack is getting snipped before it reaches your code. I believe sbt should tell you how to get the whole stack trace. Any chance you could show us the whole stack trace, or at least until you see the name of your source code file in the stack trace?Jack Koenig
I updated the stack trace. Took me some time to figure out how to get the full stack trace. Sorry about that.isururathnayaka

2 Answers

3
votes

It would help to have more of the code with line numbers, but based on the name of the trait MemOpConstants, I would guess that it includes some Chisel literals. The compiler is complaining it cannot make an IO port out of MemPortIO since it contains a Bundle MemReq which contains literals as elements.

IO Ports may only contain pure, unbound Chisel data types, not literals, Reg's, Mem's, or Wire's.

If you want to make the constants available at the IO Ports, you should define slots (UInts) to receive them, and then wire those slots up to the actual constant/literal value. Don't place the constants themselves in the IO Port definition.

1
votes

All your definitions in MemOpConstants are literals (constants) of type Bits. They have values and widths. The values are what make them literals (constants), and unsuitable for inclusion in an IO Port definition.