From f29cab9bc5912f6af7bcbe67a8c11ac722a6662f Mon Sep 17 00:00:00 2001 From: Lux Date: Wed, 19 Mar 2025 15:41:22 -0700 Subject: [PATCH 01/18] ADD: initial CTC->TL converter --- src/main/scala/ctc/CTCToTileLink.scala | 167 +++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/main/scala/ctc/CTCToTileLink.scala diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala new file mode 100644 index 00000000..5eb97ea4 --- /dev/null +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -0,0 +1,167 @@ +package testchipip.ctc + +import chisel3._ +import chisel3.util._ +import testchipip.serdes._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ +import org.chipsalliance.cde.config.{Parameters, Field} + +object CTC { + val INNER_WIDTH = 32 + val OUTER_WIDTH = 4 +} + +object CTCCommand { + val read_req = 0.U + val write_req = 1.U + val read_ack = 2.U + val write_ack = 3.U +} + +// a tl-client (master) device +// from outer: receives read and write requests in CTC +// to inner: sends read and write requests in TL +// from inner: receives read and write responses in TL +// to outer: sends read and write responses in CTC +class CTCToTileLink(sourceIds: Int = 1)(implicit p: Parameters) extends LazyModule { + val node = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLClientParameters( + name = "ctc", sourceId = IdRange(0, sourceIds)))))) + + lazy val module = new CTCToTileLinkModule(this) +} + +class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { + val io = IO(new Bundle { + val flit = new DecoupledFlitIO(CTC.INNER_WIDTH) + }) + + val (mem, edge) = outer.node.out(0) + require (edge.manager.minLatency > 0) + + // constants + val pAddrBits = edge.bundle.addressBits + val wordLen = 64 + val nChunksPerWord = wordLen / CTC.INNER_WIDTH + val cmdLen = 2 + val lenLen = 16 + val dataBits = mem.params.dataBits + val beatBytes = dataBits / 8 + val nChunksPerBeat = dataBits / CTC.INNER_WIDTH + val byteAddrBits = log2Ceil(beatBytes) + + val beatAddr = addr(pAddrBits - 1, byteAddrBits) + val nextAddr = Cat(beatAddr + 1.U, 0.U(byteAddrBits.W)) + + val len = Reg(UInt(lenLen.W)) + val cmd = Reg(UInt(cmdLen.W)) + val addr = Reg(UInt(wordLen.W)) + val body = Reg(Vec(nChunksPerBeat, UInt(CTC.INNER_WIDTH.W))) + val bodyValid = Reg(UInt(nChunksPerBeat.W)) + val ack = Reg(Bool()) + + val wmask = FillInterleaved(CTC.INNER_WIDTH/8, bodyValid) + + // tl requests + val tl_read_req = edge.Get( + fromSource = 0.U, toAddress = addr, lgSize = log2Ceil(beatBytes).U)._2 + val tl_write_req = edge.Put( + fromSource = 0.U, toAddress = addr, lgSize = log2Ceil(beatBytes).U, + data = body.asUInt, mask = wmask)._2 + + val (s_cmd :: s_addr :: s_r_req :: s_r_data :: s_r_ack :: s_r_body :: + s_w_body :: s_w_data :: s_w_ack :: Nil) = Enum(10) + val state = RegInit(s_cmd) + val idx = Reg(UInt(log2Up(nChunksPerWord).W)) + + // state-driven signals + io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) + io.flit.out.valid := state === s_r_ack || state === s_r_body || state === s_w_ack + io.flit.out.bits := Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len), // read ack header + Mux(state === s_w_ack, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header + body(idx))) // data flit + + mem.a.valid := state.isOneOf(s_r_req, s_w_data) + mem.a.bits := Mux(state === s_r_req, tl_read_req, tl_write_req) + mem.b.ready := false.B + mem.c.valid := false.B + mem.d.ready := state.isOneOf(s_r_ack, s_w_ack) + mem.e.valid := false.B + + when (state === s_cmd && io.flit.in.valid) { + len := io.flit.in.bits.flit(lenLen - 1, 0) + 1.U(lenLen.W) // always pad +1 + cmd := io.flit.in.bits.flit(cmdLen + lenLen - 1, lenLen) + addr := 0.U + idx := 0.U + ack := false.B + state := s_addr + } + + when (state === s_addr && io.flit.in.valid) { + // older flits are at higher indices + addr := (addr << CTC.INNER_WIDTH) | io.flit.in.bits.flit + idx := idx + 1.U + when (idx === (nChunksPerWord - 1).U) { + idx := 0.U + when (cmd === CTCCommand.read_req) { + state := s_r_req + } .elsewhen (cmd === CTCCommand.write_req) { + state := s_w_body + } .otherwise { + assert(false.B, "Bad CTC command") + } + } + } + + // BEGIN: handling read requests + // send read request to inner TL + when (state === s_r_req && mem.a.ready) { + state := s_r_data + } + // wait for read data from inner TL to arrive + when (state === s_r_data && mem.d.valid) { + body := mem.d.bits.data.asTypeOf(body) + state := Mux(ack, s_r_ack, s_r_body) // if ack is not sent, send acknowledgement header first + } + when (state === s_r_ack && io.flit.out.ready) { + ack := true.B // set ack flag to true + state := s_r_body + } + when (state === s_r_body && io.flit.out.ready) { + idx := idx + 1.U + len := len - 1.U + when (len === 0.U) { state := s_cmd } // fully finished handling a CTC R Request + .elsewhen (idx === (nChunksPerBeat - 1).U) { state := s_r_req } // send next TL R Request + } + // END: handling read requests + + // BEGIN: handling write requests + when (state === s_w_body && io.flit.in.valid) { + body(idx) := io.flit.in.bits + bodyValid := bodyValid | UIntToOH(idx) + when (idx === (nChunksPerBeat - 1).U || len === 0.U) { + state := s_w_data + } .otherwise { + idx := idx + 1.U + len := len - 1.U + } + } + + when (state === s_w_data && mem.a.ready) { + state := s_w_ack + } + + when (state === s_w_ack && mem.d.valid) { + when (len === 0.U) { + state := s_cmd + } .otherwise { + addr := addr + 1.U + len := len - 1.U + idx := 0.U + bodyValid := 0.U + state := s_w_body + } + } + // END: handling write requests +} \ No newline at end of file From b5b8d19d6ab2430b66ea67e60f8a22bb66f9ad6a Mon Sep 17 00:00:00 2001 From: Lux Date: Wed, 19 Mar 2025 16:10:16 -0700 Subject: [PATCH 02/18] ADD: skeleton refactor to TL->CTC --- src/main/scala/ctc/CTC.scala | 15 ++++++++++++ src/main/scala/ctc/CTCToTileLink.scala | 12 --------- src/main/scala/ctc/TileLinkToCTC.scala | 34 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 src/main/scala/ctc/CTC.scala create mode 100644 src/main/scala/ctc/TileLinkToCTC.scala diff --git a/src/main/scala/ctc/CTC.scala b/src/main/scala/ctc/CTC.scala new file mode 100644 index 00000000..582a5597 --- /dev/null +++ b/src/main/scala/ctc/CTC.scala @@ -0,0 +1,15 @@ +package testchipip.ctc + +import chisel3._ + +object CTC { + val INNER_WIDTH = 32 + val OUTER_WIDTH = 4 +} + +object CTCCommand { + val read_req = 0.U + val write_req = 1.U + val read_ack = 2.U + val write_ack = 3.U +} \ No newline at end of file diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 5eb97ea4..3f90ef1a 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -8,18 +8,6 @@ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util._ import org.chipsalliance.cde.config.{Parameters, Field} -object CTC { - val INNER_WIDTH = 32 - val OUTER_WIDTH = 4 -} - -object CTCCommand { - val read_req = 0.U - val write_req = 1.U - val read_ack = 2.U - val write_ack = 3.U -} - // a tl-client (master) device // from outer: receives read and write requests in CTC // to inner: sends read and write requests in TL diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala new file mode 100644 index 00000000..74383f7f --- /dev/null +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -0,0 +1,34 @@ +package testchipip.ctc + +import chisel3._ +import chisel3.util._ +import testchipip.serdes._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ +import org.chipsalliance.cde.config.{Parameters, Field} + +// a tl-manager (slave) device +// from inner: receives read and write requests in TL +// to outer: sends read and write requests in CTC +// from outer: receives read and write responses in CTC +// to inner: sends read and write responses in TL +class TileLinkToCTC(sinkIds: Int = 1, beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024) + (implicit p: Parameters) extends LazyModule { + val addrSet = AddressSet(baseAddr, size - 1) + val node = TLManagerNode(Seq(TLSlavePortParameters.v1( + managers = Seq(TLSlaveParameters.v2( + address = Seq(addrSet), + )), + beatBytes = beatBytes))) + + lazy val module = new TileLinkToCTCModule(this) +} + +class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { + val io = IO(new Bundle { + val flit = new DecoupledFlitIO(CTC.INNER_WIDTH) + }) + + val (mem, edge) = outer.node.in(0) +} \ No newline at end of file From cda10eaf286f69b51df92bf3125417c100c06b13 Mon Sep 17 00:00:00 2001 From: Lux Date: Wed, 19 Mar 2025 21:04:05 -0700 Subject: [PATCH 03/18] ADD: WIP for TL->CTC --- src/main/scala/ctc/CTCToTileLink.scala | 8 ++-- src/main/scala/ctc/TileLinkToCTC.scala | 64 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 3f90ef1a..69da2e7c 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -29,11 +29,11 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { require (edge.manager.minLatency > 0) // constants - val pAddrBits = edge.bundle.addressBits - val wordLen = 64 - val nChunksPerWord = wordLen / CTC.INNER_WIDTH val cmdLen = 2 val lenLen = 16 + val wordLen = 64 + val pAddrBits = edge.bundle.addressBits + val nChunksPerWord = wordLen / CTC.INNER_WIDTH val dataBits = mem.params.dataBits val beatBytes = dataBits / 8 val nChunksPerBeat = dataBits / CTC.INNER_WIDTH @@ -65,7 +65,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) - io.flit.out.valid := state === s_r_ack || state === s_r_body || state === s_w_ack + io.flit.out.valid := state.isOneOf(s_r_ack, s_r_body, s_w_ack) io.flit.out.bits := Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len), // read ack header Mux(state === s_w_ack, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header body(idx))) // data flit diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 74383f7f..78b14a70 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -31,4 +31,68 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { }) val (mem, edge) = outer.node.in(0) + + // constants + val cmdLen = 2 + val lenLen = 16 + val wordLen = 64 + val dataBits = mem.params.dataBits + val beatBytes = dataBits / 8 + val nChunksPerBeat = dataBits / CTC.INNER_WIDTH + val byteAddrBits = log2Ceil(beatBytes) + val nChunksPerWord = wordLen / CTC.INNER_WIDTH + + val len = Reg(UInt(lenLen.W)) + val cmd = Reg(UInt(cmdLen.W)) + val addr = Reg(UInt(wordLen.W)) + val body = Reg(Vec(nChunksPerBeat, UInt(CTC.INNER_WIDTH.W))) + + val (s_idle :: s_cmd :: s_addr :: s_r_body :: s_r_ack :: Nil) = Enum(6) + val state = RegInit(s_idle) + val idx = Reg(UInt(log2Up(nChunksPerWord).W)) + + // state-driven signals + io.flit.in.ready := state.isOneOf(s_r_body) + io.flit.out.valid:= state.isOneOf(s_cmd, s_addr) + io.flit.out.bits := Mux(state === s_cmd, Cat(cmd, len), + Mux(state === s_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) // TODO: add the rest of the data here + + mem.a.ready := state === s_idle + mem.b.valid := false.B + mem.c.ready := false.B + mem.d.valid := state === s_r_ack + mem.e.ready := false.B + + when (state === s_idle && mem.a.valid) { + len := mem.a.bits.size + cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) + addr := mem.a.bits.address + state := s_cmd + } + + when (state === s_cmd && io.flit.out.ready) { + state := s_addr + } + + when (state === s_addr && io.flit.out.ready) { + addr := (addr >> CTC.INNER_WIDTH) + idx := idx + 1.U + when (idx === (nChunksPerWord - 1).U) { + idx := 0.U + state := s_r_body + } + } + + when (state === s_r_body && io.flit.in.valid) { + body(idx) := io.flit.in.bits.flit + idx := idx + 1.U + when (idx === len - 1.U) { + idx := 0.U + state := s_r_ack + } + } + + when (state === s_r_ack && mem.d.ready) { + state := s_idle + } } \ No newline at end of file From b9ea79af10788f4e04e20caaaa28f13272f4ef66 Mon Sep 17 00:00:00 2001 From: Lux Date: Thu, 20 Mar 2025 13:04:22 -0700 Subject: [PATCH 04/18] ADD: write handling for TL->CTC --- src/main/scala/ctc/TileLinkToCTC.scala | 70 ++++++++++++++++++++------ 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 78b14a70..66ebb211 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -38,51 +38,74 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val wordLen = 64 val dataBits = mem.params.dataBits val beatBytes = dataBits / 8 + val maxBeats = 1 val nChunksPerBeat = dataBits / CTC.INNER_WIDTH val byteAddrBits = log2Ceil(beatBytes) val nChunksPerWord = wordLen / CTC.INNER_WIDTH + val maxChunks = maxBeats * nChunksPerBeat val len = Reg(UInt(lenLen.W)) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) - val body = Reg(Vec(nChunksPerBeat, UInt(CTC.INNER_WIDTH.W))) + val body = Reg(Vec(maxChunks, UInt(CTC.INNER_WIDTH.W))) - val (s_idle :: s_cmd :: s_addr :: s_r_body :: s_r_ack :: Nil) = Enum(6) + val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: + s_r_body :: s_r_ack :: s_w_body :: s_w_ack :: Nil) = Enum(8) val state = RegInit(s_idle) val idx = Reg(UInt(log2Up(nChunksPerWord).W)) // state-driven signals - io.flit.in.ready := state.isOneOf(s_r_body) - io.flit.out.valid:= state.isOneOf(s_cmd, s_addr) - io.flit.out.bits := Mux(state === s_cmd, Cat(cmd, len), - Mux(state === s_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) // TODO: add the rest of the data here + io.flit.in.ready := state.isOneOf(s_r_body, s_w_body) + io.flit.out.valid:= state.isOneOf(s_send_cmd, s_send_addr, s_recv_cmd, s_recv_addr) + io.flit.out.bits := Mux(state === s_send_cmd, Cat(cmd, len), + Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) // TODO: add the rest of the data here mem.a.ready := state === s_idle mem.b.valid := false.B mem.c.ready := false.B - mem.d.valid := state === s_r_ack + mem.d.valid := state.isOneOf(s_r_ack, s_w_ack) mem.e.ready := false.B when (state === s_idle && mem.a.valid) { len := mem.a.bits.size cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) addr := mem.a.bits.address - state := s_cmd + state := s_send_cmd + when (cmd === CTCCommand.write_req) { + body := mem.a.bits.data.asTypeOf(body) + } } - when (state === s_cmd && io.flit.out.ready) { - state := s_addr + when (state === s_send_cmd && io.flit.out.ready) { + state := s_send_addr } - when (state === s_addr && io.flit.out.ready) { + when (state === s_send_addr && io.flit.out.ready) { addr := (addr >> CTC.INNER_WIDTH) idx := idx + 1.U when (idx === (nChunksPerWord - 1).U) { idx := 0.U - state := s_r_body + state := Mux(cmd === CTCCommand.read_req, s_recv_cmd, s_w_body) } } + when (state === s_recv_cmd && io.flit.in.valid) { + assert(io.flit.in.bits.flit === cmd, "Mismatch in CTC command") + state := s_recv_addr + } + + when (state === s_recv_addr && io.flit.in.valid) { + assert(io.flit.in.bits.flit === ((addr >> (idx * CTC.INNER_WIDTH.U)) & ((1.U << CTC.INNER_WIDTH.U) - 1.U)), "Mismatch in CTC address") + when (idx === (nChunksPerWord - 1).U) { + idx := 0.U + state := Mux(cmd === CTCCommand.read_req, s_r_body, s_w_ack) + } .otherwise { + idx := idx + 1.U + } + } + + // BEGIN: handling read requests + // wait and collect the read response when (state === s_r_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.flit idx := idx + 1.U @@ -91,8 +114,27 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { state := s_r_ack } } - + // send the read acknoledgement to TL when (state === s_r_ack && mem.d.ready) { state := s_idle - } + } + // END: handling read requests + + // BEGIN: handling write requests + // send the write data to CTC + when (state === s_w_body && io.flit.in.valid) { + body(idx) := io.flit.in.bits.flit + idx := idx + 1.U + when (idx === len - 1.U) { + idx := 0.U + state := s_recv_cmd + } + } + + // send the write acknoledgement to TL + when (state === s_w_ack && mem.d.ready) { + state := s_idle + } + + // END: handling write requests } \ No newline at end of file From 1cb2908dc6f9920ce8d5ebd28052c6059ae3f1fc Mon Sep 17 00:00:00 2001 From: Lux Date: Thu, 20 Mar 2025 14:34:44 -0700 Subject: [PATCH 05/18] ADD: unittest, fully elaborates --- src/main/scala/ctc/CTCToTileLink.scala | 13 +++--- src/main/scala/ctc/TileLinkToCTC.scala | 17 +++++--- src/main/scala/test/Unittests.scala | 60 +++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 69da2e7c..2182aaa7 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -39,9 +39,6 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { val nChunksPerBeat = dataBits / CTC.INNER_WIDTH val byteAddrBits = log2Ceil(beatBytes) - val beatAddr = addr(pAddrBits - 1, byteAddrBits) - val nextAddr = Cat(beatAddr + 1.U, 0.U(byteAddrBits.W)) - val len = Reg(UInt(lenLen.W)) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) @@ -49,6 +46,9 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { val bodyValid = Reg(UInt(nChunksPerBeat.W)) val ack = Reg(Bool()) + val beatAddr = addr(pAddrBits - 1, byteAddrBits) + val nextAddr = Cat(beatAddr + 1.U, 0.U(byteAddrBits.W)) + val wmask = FillInterleaved(CTC.INNER_WIDTH/8, bodyValid) // tl requests @@ -59,16 +59,17 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { data = body.asUInt, mask = wmask)._2 val (s_cmd :: s_addr :: s_r_req :: s_r_data :: s_r_ack :: s_r_body :: - s_w_body :: s_w_data :: s_w_ack :: Nil) = Enum(10) + s_w_body :: s_w_data :: s_w_ack :: Nil) = Enum(9) val state = RegInit(s_cmd) val idx = Reg(UInt(log2Up(nChunksPerWord).W)) // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) io.flit.out.valid := state.isOneOf(s_r_ack, s_r_body, s_w_ack) - io.flit.out.bits := Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len), // read ack header + val out_bits = Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len), // read ack header Mux(state === s_w_ack, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header body(idx))) // data flit + io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) mem.a.valid := state.isOneOf(s_r_req, s_w_data) mem.a.bits := Mux(state === s_r_req, tl_read_req, tl_write_req) @@ -126,7 +127,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // BEGIN: handling write requests when (state === s_w_body && io.flit.in.valid) { - body(idx) := io.flit.in.bits + body(idx) := io.flit.in.bits.asUInt bodyValid := bodyValid | UIntToOH(idx) when (idx === (nChunksPerBeat - 1).U || len === 0.U) { state := s_w_data diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 66ebb211..2c9093cd 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -13,13 +13,18 @@ import org.chipsalliance.cde.config.{Parameters, Field} // to outer: sends read and write requests in CTC // from outer: receives read and write responses in CTC // to inner: sends read and write responses in TL -class TileLinkToCTC(sinkIds: Int = 1, beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024) +class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024, maxWidth: Int = 64) (implicit p: Parameters) extends LazyModule { val addrSet = AddressSet(baseAddr, size - 1) val node = TLManagerNode(Seq(TLSlavePortParameters.v1( managers = Seq(TLSlaveParameters.v2( - address = Seq(addrSet), - )), + address = Seq(addrSet), + regionType = RegionType.UNCACHED, + supports = TLMasterToSlaveTransferSizes( + putFull = TransferSizes(1, maxWidth), + get = TransferSizes(1, maxWidth) + ), + fifoId = Some(0))), // requests are handled in order beatBytes = beatBytes))) lazy val module = new TileLinkToCTCModule(this) @@ -38,6 +43,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val wordLen = 64 val dataBits = mem.params.dataBits val beatBytes = dataBits / 8 + assert(beatBytes == outer.beatBytes, "Beat bytes mismatch") val maxBeats = 1 val nChunksPerBeat = dataBits / CTC.INNER_WIDTH val byteAddrBits = log2Ceil(beatBytes) @@ -50,15 +56,16 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val body = Reg(Vec(maxChunks, UInt(CTC.INNER_WIDTH.W))) val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: - s_r_body :: s_r_ack :: s_w_body :: s_w_ack :: Nil) = Enum(8) + s_r_body :: s_r_ack :: s_w_body :: s_w_ack :: Nil) = Enum(9) val state = RegInit(s_idle) val idx = Reg(UInt(log2Up(nChunksPerWord).W)) // state-driven signals io.flit.in.ready := state.isOneOf(s_r_body, s_w_body) io.flit.out.valid:= state.isOneOf(s_send_cmd, s_send_addr, s_recv_cmd, s_recv_addr) - io.flit.out.bits := Mux(state === s_send_cmd, Cat(cmd, len), + val out_bits = Mux(state === s_send_cmd, Cat(cmd, len), Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) // TODO: add the rest of the data here + io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) mem.a.ready := state === s_idle mem.b.valid := false.B diff --git a/src/main/scala/test/Unittests.scala b/src/main/scala/test/Unittests.scala index e704f647..5dc91200 100644 --- a/src/main/scala/test/Unittests.scala +++ b/src/main/scala/test/Unittests.scala @@ -17,7 +17,7 @@ import testchipip.serdes._ import testchipip.soc._ import testchipip.util._ import testchipip.tsi._ - +import testchipip.ctc._ class BlockDeviceTrackerTestDriver(nSectors: Int)(implicit p: Parameters) extends LazyModule with HasBlockDeviceParameters { val bdParams = p(BlockDeviceKey).get @@ -297,6 +297,61 @@ class BidirectionalSerdesTestWrapper(phyParams: SerialPhyParams, timeout: Int = when (testReset && io.start) { testReset := false.B } } +class TLCTCTest(phyParams: SerialPhyParams)(implicit p: Parameters) extends LazyModule { + val numChannels = 2 + val beatBytes = 8 + + val fuzzers = Seq.fill(2) { LazyModule(new TLFuzzer( + nOperations = 32, + inFlight = 1)) } + + val tl2ctc = Seq.fill(2) { LazyModule(new TileLinkToCTC(beatBytes = beatBytes)) } + val ctc2tl = Seq.fill(2) { LazyModule(new CTCToTileLink()) } + + val testrams = Seq.fill(2) { LazyModule(new TLTestRAM( + address = AddressSet(0, 0xffff), + beatBytes = beatBytes)) } + + tl2ctc(0).node := TLBuffer() := fuzzers(0).node + tl2ctc(1).node := TLBuffer() := fuzzers(1).node + + testrams(0).node := TLBuffer() := ctc2tl(0).node + testrams(1).node := TLBuffer() := ctc2tl(1).node + + lazy val module = new Impl + class Impl extends LazyModuleImp(this) { + val io = IO(new Bundle { val finished = Output(Bool()) }) + phyParams match { + case params: CreditedSourceSyncSerialPhyParams => { + val phys = Seq.fill(2) { + val phy = Module(new CreditedSerialPhy(numChannels, params)) + phy.io.outgoing_clock := clock + phy.io.incoming_clock := clock + phy.io.inner_clock := clock + phy.io.outgoing_reset := reset + phy.io.incoming_reset := reset + phy.io.inner_reset := reset + phy + } + phys(0).io.inner_ser(0) <> tl2ctc(0).module.io.flit + phys(0).io.inner_ser(1) <> ctc2tl(0).module.io.flit + phys(1).io.inner_ser(0) <> tl2ctc(1).module.io.flit + phys(1).io.inner_ser(1) <> ctc2tl(1).module.io.flit + phys(0).io.outer_ser.in <> phys(1).io.outer_ser.out + phys(1).io.outer_ser.in <> phys(0).io.outer_ser.out + } + } + io.finished := fuzzers.map(_.module.io.finished).andR + } +} + +class TLCTCTestWrapper(phyParams: SerialPhyParams, timeout: Int = 4096)(implicit p: Parameters) extends UnitTest(timeout) { + val testReset = RegInit(true.B) + val test = Module(LazyModule(new TLCTCTest(phyParams)).module) + io.finished := test.io.finished + test.reset := testReset || reset.asBool + when (testReset && io.start) { testReset := false.B } +} class StreamWidthAdapterTest extends UnitTest { val smaller = Wire(new StreamIO(16)) val larger = Wire(new StreamIO(64)) @@ -568,6 +623,7 @@ object TestChipUnitTests { Module(new SwitchTestWrapper), Module(new StreamWidthAdapterTest), Module(new NetworkXbarTest), - Module(new TLRingNetworkTestWrapper) + Module(new TLRingNetworkTestWrapper), + Module(new TLCTCTestWrapper(CreditedSourceSyncSerialPhyParams(flitWidth = 32, phitWidth = 4), 10000)) ) } From 9b8a89c4567904fcfdf7b7b4a087812a166b9273 Mon Sep 17 00:00:00 2001 From: Lux Date: Thu, 20 Mar 2025 18:31:39 -0700 Subject: [PATCH 06/18] ADD: somewhat working --- src/main/scala/ctc/CTCToTileLink.scala | 8 +++--- src/main/scala/ctc/TileLinkToCTC.scala | 37 +++++++++++++++++--------- src/main/scala/test/Unittests.scala | 5 ++-- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 2182aaa7..0bbf9c70 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -66,7 +66,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) io.flit.out.valid := state.isOneOf(s_r_ack, s_r_body, s_w_ack) - val out_bits = Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len), // read ack header + val out_bits = Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len - 1.U), // read ack header Mux(state === s_w_ack, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header body(idx))) // data flit io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) @@ -75,7 +75,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { mem.a.bits := Mux(state === s_r_req, tl_read_req, tl_write_req) mem.b.ready := false.B mem.c.valid := false.B - mem.d.ready := state.isOneOf(s_r_ack, s_w_ack) + mem.d.ready := state.isOneOf(s_r_data, s_w_ack) mem.e.valid := false.B when (state === s_cmd && io.flit.in.valid) { @@ -89,7 +89,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { when (state === s_addr && io.flit.in.valid) { // older flits are at higher indices - addr := (addr << CTC.INNER_WIDTH) | io.flit.in.bits.flit + addr := addr | (io.flit.in.bits.flit << (idx * CTC.INNER_WIDTH.U)) idx := idx + 1.U when (idx === (nChunksPerWord - 1).U) { idx := 0.U @@ -111,7 +111,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // wait for read data from inner TL to arrive when (state === s_r_data && mem.d.valid) { body := mem.d.bits.data.asTypeOf(body) - state := Mux(ack, s_r_ack, s_r_body) // if ack is not sent, send acknowledgement header first + state := Mux(~ack, s_r_ack, s_r_body) // if ack is not sent, send acknowledgement header first } when (state === s_r_ack && io.flit.out.ready) { ack := true.B // set ack flag to true diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 2c9093cd..a6d21f7b 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -13,7 +13,7 @@ import org.chipsalliance.cde.config.{Parameters, Field} // to outer: sends read and write requests in CTC // from outer: receives read and write responses in CTC // to inner: sends read and write responses in TL -class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024, maxWidth: Int = 64) +class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024, val maxWidth: Int = 64) (implicit p: Parameters) extends LazyModule { val addrSet = AddressSet(baseAddr, size - 1) val node = TLManagerNode(Seq(TLSlavePortParameters.v1( @@ -21,8 +21,8 @@ class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = address = Seq(addrSet), regionType = RegionType.UNCACHED, supports = TLMasterToSlaveTransferSizes( - putFull = TransferSizes(1, maxWidth), - get = TransferSizes(1, maxWidth) + putFull = TransferSizes(beatBytes, beatBytes), // for now, only support single beat + get = TransferSizes(beatBytes, beatBytes) ), fifoId = Some(0))), // requests are handled in order beatBytes = beatBytes))) @@ -36,6 +36,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { }) val (mem, edge) = outer.node.in(0) + dontTouch(mem.d.bits.size) // constants val cmdLen = 2 @@ -51,6 +52,8 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val maxChunks = maxBeats * nChunksPerBeat val len = Reg(UInt(lenLen.W)) + val lg_size = Reg(UInt(log2Ceil(beatBytes * maxBeats).W)) + dontTouch(lg_size) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) val body = Reg(Vec(maxChunks, UInt(CTC.INNER_WIDTH.W))) @@ -58,26 +61,33 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: s_r_body :: s_r_ack :: s_w_body :: s_w_ack :: Nil) = Enum(9) val state = RegInit(s_idle) - val idx = Reg(UInt(log2Up(nChunksPerWord).W)) + val idx = Reg(UInt(log2Up(beatBytes).W)) // state-driven signals - io.flit.in.ready := state.isOneOf(s_r_body, s_w_body) - io.flit.out.valid:= state.isOneOf(s_send_cmd, s_send_addr, s_recv_cmd, s_recv_addr) - val out_bits = Mux(state === s_send_cmd, Cat(cmd, len), + io.flit.in.ready := state.isOneOf(s_r_body, s_w_body, s_recv_cmd, s_recv_addr) + io.flit.out.valid:= state.isOneOf(s_send_cmd, s_send_addr, s_w_body) + val out_bits = Mux(state === s_send_cmd, Cat(cmd, len - 1.U), Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) // TODO: add the rest of the data here io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) + val tl_write_ack = edge.AccessAck(0.U, lg_size) + val tl_read_ack = edge.AccessAck(0.U, lg_size, body.asUInt) + mem.a.ready := state === s_idle mem.b.valid := false.B mem.c.ready := false.B - mem.d.valid := state.isOneOf(s_r_ack, s_w_ack) + mem.d.valid := state.isOneOf(s_r_ack, s_w_ack) + mem.d.bits := Mux(state === s_r_ack, tl_read_ack, tl_write_ack) mem.e.ready := false.B + when (state === s_idle && mem.a.valid) { - len := mem.a.bits.size + len := (1.U << mem.a.bits.size) / beatBytes.U + lg_size := mem.a.bits.size cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) addr := mem.a.bits.address state := s_send_cmd + idx := 0.U when (cmd === CTCCommand.write_req) { body := mem.a.bits.data.asTypeOf(body) } @@ -97,12 +107,14 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { } when (state === s_recv_cmd && io.flit.in.valid) { - assert(io.flit.in.bits.flit === cmd, "Mismatch in CTC command") + assert(io.flit.in.bits.flit(lenLen - 1, 0) === len - 1.U, "Mismatch in CTC length") + val ack_cmd = Mux(cmd === CTCCommand.read_req, CTCCommand.read_ack, CTCCommand.write_ack) + assert(io.flit.in.bits.flit(cmdLen + lenLen - 1, lenLen) === ack_cmd, "Mismatch in CTC command") state := s_recv_addr } when (state === s_recv_addr && io.flit.in.valid) { - assert(io.flit.in.bits.flit === ((addr >> (idx * CTC.INNER_WIDTH.U)) & ((1.U << CTC.INNER_WIDTH.U) - 1.U)), "Mismatch in CTC address") + // assert(io.flit.in.bits.flit === ((addr >> (idx * CTC.INNER_WIDTH.U)) & ((1.U << CTC.INNER_WIDTH.U) - 1.U)), "Mismatch in CTC address") when (idx === (nChunksPerWord - 1).U) { idx := 0.U state := Mux(cmd === CTCCommand.read_req, s_r_body, s_w_ack) @@ -113,8 +125,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // BEGIN: handling read requests // wait and collect the read response - when (state === s_r_body && io.flit.in.valid) { - body(idx) := io.flit.in.bits.flit + when (state === s_r_body && io.flit.out.ready) { idx := idx + 1.U when (idx === len - 1.U) { idx := 0.U diff --git a/src/main/scala/test/Unittests.scala b/src/main/scala/test/Unittests.scala index 5dc91200..f734ef13 100644 --- a/src/main/scala/test/Unittests.scala +++ b/src/main/scala/test/Unittests.scala @@ -335,8 +335,8 @@ class TLCTCTest(phyParams: SerialPhyParams)(implicit p: Parameters) extends Lazy } phys(0).io.inner_ser(0) <> tl2ctc(0).module.io.flit phys(0).io.inner_ser(1) <> ctc2tl(0).module.io.flit - phys(1).io.inner_ser(0) <> tl2ctc(1).module.io.flit - phys(1).io.inner_ser(1) <> ctc2tl(1).module.io.flit + phys(1).io.inner_ser(0) <> ctc2tl(1).module.io.flit + phys(1).io.inner_ser(1) <> tl2ctc(1).module.io.flit phys(0).io.outer_ser.in <> phys(1).io.outer_ser.out phys(1).io.outer_ser.in <> phys(0).io.outer_ser.out } @@ -352,6 +352,7 @@ class TLCTCTestWrapper(phyParams: SerialPhyParams, timeout: Int = 4096)(implicit test.reset := testReset || reset.asBool when (testReset && io.start) { testReset := false.B } } + class StreamWidthAdapterTest extends UnitTest { val smaller = Wire(new StreamIO(16)) val larger = Wire(new StreamIO(64)) From 9245e2deec1149a2d0f22c7095faa2ee29a7aa05 Mon Sep 17 00:00:00 2001 From: Lux Date: Thu, 20 Mar 2025 21:52:00 -0700 Subject: [PATCH 07/18] FIX: passes unittest --- src/main/scala/ctc/CTCToTileLink.scala | 44 ++++++++++++++++++-------- src/main/scala/ctc/TileLinkToCTC.scala | 15 +++++---- src/main/scala/test/Unittests.scala | 2 +- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 0bbf9c70..0c068e20 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -57,25 +57,27 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { val tl_write_req = edge.Put( fromSource = 0.U, toAddress = addr, lgSize = log2Ceil(beatBytes).U, data = body.asUInt, mask = wmask)._2 - - val (s_cmd :: s_addr :: s_r_req :: s_r_data :: s_r_ack :: s_r_body :: - s_w_body :: s_w_data :: s_w_ack :: Nil) = Enum(9) + + // ====== state machine ====== + val (s_cmd :: s_addr :: s_r_req :: s_r_data :: s_send_ack :: s_send_addr :: s_r_body :: + s_w_body :: s_w_data :: s_w_wait :: Nil) = Enum(10) val state = RegInit(s_cmd) val idx = Reg(UInt(log2Up(nChunksPerWord).W)) // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) - io.flit.out.valid := state.isOneOf(s_r_ack, s_r_body, s_w_ack) - val out_bits = Mux(state === s_r_ack, Cat(CTCCommand.read_ack, len - 1.U), // read ack header - Mux(state === s_w_ack, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header - body(idx))) // data flit + io.flit.out.valid := state.isOneOf(s_send_ack, s_send_addr, s_r_body) + val out_bits = Mux(state === s_send_ack && cmd === CTCCommand.read_req, Cat(CTCCommand.read_ack, len - 1.U), // read ack header + Mux(state === s_send_ack && cmd === CTCCommand.write_req, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header + Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), // send address header + body(idx)))) // data flit io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) mem.a.valid := state.isOneOf(s_r_req, s_w_data) mem.a.bits := Mux(state === s_r_req, tl_read_req, tl_write_req) mem.b.ready := false.B mem.c.valid := false.B - mem.d.ready := state.isOneOf(s_r_data, s_w_ack) + mem.d.ready := state.isOneOf(s_r_data, s_w_wait) mem.e.valid := false.B when (state === s_cmd && io.flit.in.valid) { @@ -111,12 +113,23 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // wait for read data from inner TL to arrive when (state === s_r_data && mem.d.valid) { body := mem.d.bits.data.asTypeOf(body) - state := Mux(~ack, s_r_ack, s_r_body) // if ack is not sent, send acknowledgement header first + state := Mux(~ack, s_send_ack, s_r_body) // if ack is not sent, send acknowledgement header first } - when (state === s_r_ack && io.flit.out.ready) { + // send the read ack to outer CTC if this is the first beat + when (state === s_send_ack && io.flit.out.ready) { ack := true.B // set ack flag to true - state := s_r_body + idx := 0.U + state := s_send_addr + } + // send the address header to outer CTC + when (state === s_send_addr && io.flit.out.ready) { + idx := idx + 1.U + addr := addr >> CTC.INNER_WIDTH.U + when (idx === (nChunksPerWord - 1).U) { + state := Mux(cmd === CTCCommand.read_req, s_r_body, s_cmd) + } } + // send the read data to outer CTC when (state === s_r_body && io.flit.out.ready) { idx := idx + 1.U len := len - 1.U @@ -126,6 +139,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // END: handling read requests // BEGIN: handling write requests + // collect the write data from the CTC when (state === s_w_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.asUInt bodyValid := bodyValid | UIntToOH(idx) @@ -137,13 +151,15 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { } } + // send the write request to inner TL when (state === s_w_data && mem.a.ready) { - state := s_w_ack + state := s_w_wait // wait for write response from inner TL } - when (state === s_w_ack && mem.d.valid) { + // wait for write response from inner TL + when (state === s_w_wait && mem.d.valid) { when (len === 0.U) { - state := s_cmd + state := s_send_ack } .otherwise { addr := addr + 1.U len := len - 1.U diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index a6d21f7b..29ea79c9 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -58,16 +58,17 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val addr = Reg(UInt(wordLen.W)) val body = Reg(Vec(maxChunks, UInt(CTC.INNER_WIDTH.W))) + // ====== state machine ====== val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: s_r_body :: s_r_ack :: s_w_body :: s_w_ack :: Nil) = Enum(9) val state = RegInit(s_idle) val idx = Reg(UInt(log2Up(beatBytes).W)) // state-driven signals - io.flit.in.ready := state.isOneOf(s_r_body, s_w_body, s_recv_cmd, s_recv_addr) + io.flit.in.ready := state.isOneOf(s_r_body, s_recv_cmd, s_recv_addr) io.flit.out.valid:= state.isOneOf(s_send_cmd, s_send_addr, s_w_body) val out_bits = Mux(state === s_send_cmd, Cat(cmd, len - 1.U), - Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) // TODO: add the rest of the data here + Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) val tl_write_ack = edge.AccessAck(0.U, lg_size) @@ -125,9 +126,10 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // BEGIN: handling read requests // wait and collect the read response - when (state === s_r_body && io.flit.out.ready) { + when (state === s_r_body && io.flit.in.valid) { + body(idx) := io.flit.in.bits.flit.asUInt idx := idx + 1.U - when (idx === len - 1.U) { + when (idx === len) { idx := 0.U state := s_r_ack } @@ -140,10 +142,9 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // BEGIN: handling write requests // send the write data to CTC - when (state === s_w_body && io.flit.in.valid) { - body(idx) := io.flit.in.bits.flit + when (state === s_w_body && io.flit.out.ready) { idx := idx + 1.U - when (idx === len - 1.U) { + when (idx === len) { idx := 0.U state := s_recv_cmd } diff --git a/src/main/scala/test/Unittests.scala b/src/main/scala/test/Unittests.scala index f734ef13..eafffb56 100644 --- a/src/main/scala/test/Unittests.scala +++ b/src/main/scala/test/Unittests.scala @@ -625,6 +625,6 @@ object TestChipUnitTests { Module(new StreamWidthAdapterTest), Module(new NetworkXbarTest), Module(new TLRingNetworkTestWrapper), - Module(new TLCTCTestWrapper(CreditedSourceSyncSerialPhyParams(flitWidth = 32, phitWidth = 4), 10000)) + Module(new TLCTCTestWrapper(CreditedSourceSyncSerialPhyParams(flitWidth = 32, phitWidth = 4), 20000)) ) } From 737fe6009cc3b650241aab37e92cac54b3f323a4 Mon Sep 17 00:00:00 2001 From: Lux Date: Thu, 20 Mar 2025 22:43:49 -0700 Subject: [PATCH 08/18] FIX: multibeat WIP, pending addr fixes --- src/main/scala/ctc/CTCToTileLink.scala | 14 +++++++------- src/main/scala/ctc/TileLinkToCTC.scala | 21 +++++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 0c068e20..ccee30a1 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -67,7 +67,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) io.flit.out.valid := state.isOneOf(s_send_ack, s_send_addr, s_r_body) - val out_bits = Mux(state === s_send_ack && cmd === CTCCommand.read_req, Cat(CTCCommand.read_ack, len - 1.U), // read ack header + val out_bits = Mux(state === s_send_ack && cmd === CTCCommand.read_req, Cat(CTCCommand.read_ack, len), // read ack header Mux(state === s_send_ack && cmd === CTCCommand.write_req, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), // send address header body(idx)))) // data flit @@ -81,7 +81,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { mem.e.valid := false.B when (state === s_cmd && io.flit.in.valid) { - len := io.flit.in.bits.flit(lenLen - 1, 0) + 1.U(lenLen.W) // always pad +1 + len := io.flit.in.bits.flit(lenLen - 1, 0) cmd := io.flit.in.bits.flit(cmdLen + lenLen - 1, lenLen) addr := 0.U idx := 0.U @@ -132,9 +132,10 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // send the read data to outer CTC when (state === s_r_body && io.flit.out.ready) { idx := idx + 1.U - len := len - 1.U - when (len === 0.U) { state := s_cmd } // fully finished handling a CTC R Request - .elsewhen (idx === (nChunksPerBeat - 1).U) { state := s_r_req } // send next TL R Request + when (idx === (nChunksPerBeat - 1).U) { + len := len - 1.U + state := Mux(len === 0.U, s_cmd, s_r_req) // send next TL R Request + } } // END: handling read requests @@ -143,11 +144,10 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { when (state === s_w_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.asUInt bodyValid := bodyValid | UIntToOH(idx) - when (idx === (nChunksPerBeat - 1).U || len === 0.U) { + when (idx === (nChunksPerBeat - 1).U) { state := s_w_data } .otherwise { idx := idx + 1.U - len := len - 1.U } } diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 29ea79c9..a6ac0138 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -13,7 +13,7 @@ import org.chipsalliance.cde.config.{Parameters, Field} // to outer: sends read and write requests in CTC // from outer: receives read and write responses in CTC // to inner: sends read and write responses in TL -class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024, val maxWidth: Int = 64) +class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024, val maxBeats: Int = 4) (implicit p: Parameters) extends LazyModule { val addrSet = AddressSet(baseAddr, size - 1) val node = TLManagerNode(Seq(TLSlavePortParameters.v1( @@ -21,8 +21,8 @@ class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = address = Seq(addrSet), regionType = RegionType.UNCACHED, supports = TLMasterToSlaveTransferSizes( - putFull = TransferSizes(beatBytes, beatBytes), // for now, only support single beat - get = TransferSizes(beatBytes, beatBytes) + putFull = TransferSizes(beatBytes, beatBytes*maxBeats), // for now, only support single beat + get = TransferSizes(beatBytes, beatBytes*maxBeats) ), fifoId = Some(0))), // requests are handled in order beatBytes = beatBytes))) @@ -45,14 +45,13 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val dataBits = mem.params.dataBits val beatBytes = dataBits / 8 assert(beatBytes == outer.beatBytes, "Beat bytes mismatch") - val maxBeats = 1 val nChunksPerBeat = dataBits / CTC.INNER_WIDTH val byteAddrBits = log2Ceil(beatBytes) val nChunksPerWord = wordLen / CTC.INNER_WIDTH - val maxChunks = maxBeats * nChunksPerBeat + val maxChunks = outer.maxBeats * nChunksPerBeat val len = Reg(UInt(lenLen.W)) - val lg_size = Reg(UInt(log2Ceil(beatBytes * maxBeats).W)) + val lg_size = Reg(UInt(log2Ceil(beatBytes * outer.maxBeats).W)) dontTouch(lg_size) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) @@ -129,14 +128,20 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { when (state === s_r_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.flit.asUInt idx := idx + 1.U - when (idx === len) { - idx := 0.U + when (idx === nChunksPerBeat.U - 1.U) { state := s_r_ack + len := len - 1.U } } // send the read acknoledgement to TL when (state === s_r_ack && mem.d.ready) { state := s_idle + when (len === 0.U) { + state := s_idle + } .otherwise { + idx := 0.U + state := s_r_body + } } // END: handling read requests From 4d61429158ed2ff1a44629eaa65fa3879f0a7fc6 Mon Sep 17 00:00:00 2001 From: Lux Date: Fri, 21 Mar 2025 14:11:46 -0700 Subject: [PATCH 09/18] FIX: now works for multi-beat --- src/main/scala/ctc/CTCToTileLink.scala | 24 +++++++++++------------- src/main/scala/ctc/TileLinkToCTC.scala | 19 ++++++++++++++----- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index ccee30a1..249c5316 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -37,26 +37,22 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { val dataBits = mem.params.dataBits val beatBytes = dataBits / 8 val nChunksPerBeat = dataBits / CTC.INNER_WIDTH - val byteAddrBits = log2Ceil(beatBytes) val len = Reg(UInt(lenLen.W)) + val ctc_len = Reg(UInt(lenLen.W)) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) + val tladdr = Reg(UInt(wordLen.W)) val body = Reg(Vec(nChunksPerBeat, UInt(CTC.INNER_WIDTH.W))) - val bodyValid = Reg(UInt(nChunksPerBeat.W)) val ack = Reg(Bool()) - val beatAddr = addr(pAddrBits - 1, byteAddrBits) - val nextAddr = Cat(beatAddr + 1.U, 0.U(byteAddrBits.W)) - - val wmask = FillInterleaved(CTC.INNER_WIDTH/8, bodyValid) + val next_tl_addr = tladdr + beatBytes.U // tl requests val tl_read_req = edge.Get( - fromSource = 0.U, toAddress = addr, lgSize = log2Ceil(beatBytes).U)._2 + fromSource = 0.U, toAddress = tladdr, lgSize = log2Ceil(beatBytes).U)._2 val tl_write_req = edge.Put( - fromSource = 0.U, toAddress = addr, lgSize = log2Ceil(beatBytes).U, - data = body.asUInt, mask = wmask)._2 + fromSource = 0.U, toAddress = tladdr, lgSize = log2Ceil(beatBytes).U, data = body.asUInt)._2 // ====== state machine ====== val (s_cmd :: s_addr :: s_r_req :: s_r_data :: s_send_ack :: s_send_addr :: s_r_body :: @@ -67,8 +63,8 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) io.flit.out.valid := state.isOneOf(s_send_ack, s_send_addr, s_r_body) - val out_bits = Mux(state === s_send_ack && cmd === CTCCommand.read_req, Cat(CTCCommand.read_ack, len), // read ack header - Mux(state === s_send_ack && cmd === CTCCommand.write_req, Cat(CTCCommand.write_ack, 0.U(lenLen.W)), // write ack header + val out_bits = Mux(state === s_send_ack && cmd === CTCCommand.read_req, Cat(CTCCommand.read_ack, ctc_len), // read ack header + Mux(state === s_send_ack && cmd === CTCCommand.write_req, Cat(CTCCommand.write_ack, ctc_len), // write ack header Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), // send address header body(idx)))) // data flit io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) @@ -82,6 +78,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { when (state === s_cmd && io.flit.in.valid) { len := io.flit.in.bits.flit(lenLen - 1, 0) + ctc_len := io.flit.in.bits.flit(lenLen - 1, 0) cmd := io.flit.in.bits.flit(cmdLen + lenLen - 1, lenLen) addr := 0.U idx := 0.U @@ -95,6 +92,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { idx := idx + 1.U when (idx === (nChunksPerWord - 1).U) { idx := 0.U + tladdr := addr when (cmd === CTCCommand.read_req) { state := s_r_req } .elsewhen (cmd === CTCCommand.write_req) { @@ -134,6 +132,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { idx := idx + 1.U when (idx === (nChunksPerBeat - 1).U) { len := len - 1.U + tladdr := next_tl_addr state := Mux(len === 0.U, s_cmd, s_r_req) // send next TL R Request } } @@ -143,7 +142,6 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // collect the write data from the CTC when (state === s_w_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.asUInt - bodyValid := bodyValid | UIntToOH(idx) when (idx === (nChunksPerBeat - 1).U) { state := s_w_data } .otherwise { @@ -162,9 +160,9 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { state := s_send_ack } .otherwise { addr := addr + 1.U + tladdr := next_tl_addr len := len - 1.U idx := 0.U - bodyValid := 0.U state := s_w_body } } diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index a6ac0138..79ac2aa7 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -51,6 +51,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val maxChunks = outer.maxBeats * nChunksPerBeat val len = Reg(UInt(lenLen.W)) + val ctc_len = Reg(UInt(lenLen.W)) val lg_size = Reg(UInt(log2Ceil(beatBytes * outer.maxBeats).W)) dontTouch(lg_size) val cmd = Reg(UInt(cmdLen.W)) @@ -59,7 +60,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // ====== state machine ====== val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: - s_r_body :: s_r_ack :: s_w_body :: s_w_ack :: Nil) = Enum(9) + s_r_body :: s_r_ack :: s_w_req :: s_w_body :: s_w_ack :: Nil) = Enum(10) val state = RegInit(s_idle) val idx = Reg(UInt(log2Up(beatBytes).W)) @@ -73,7 +74,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val tl_write_ack = edge.AccessAck(0.U, lg_size) val tl_read_ack = edge.AccessAck(0.U, lg_size, body.asUInt) - mem.a.ready := state === s_idle + mem.a.ready := state.isOneOf(s_idle, s_w_req) mem.b.valid := false.B mem.c.ready := false.B mem.d.valid := state.isOneOf(s_r_ack, s_w_ack) @@ -83,6 +84,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { when (state === s_idle && mem.a.valid) { len := (1.U << mem.a.bits.size) / beatBytes.U + ctc_len := (1.U << mem.a.bits.size) / beatBytes.U lg_size := mem.a.bits.size cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) addr := mem.a.bits.address @@ -107,7 +109,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { } when (state === s_recv_cmd && io.flit.in.valid) { - assert(io.flit.in.bits.flit(lenLen - 1, 0) === len - 1.U, "Mismatch in CTC length") + assert((io.flit.in.bits.flit(lenLen - 1, 0) === ctc_len - 1.U), "Mismatch in CTC length") val ack_cmd = Mux(cmd === CTCCommand.read_req, CTCCommand.read_ack, CTCCommand.write_ack) assert(io.flit.in.bits.flit(cmdLen + lenLen - 1, lenLen) === ack_cmd, "Mismatch in CTC command") state := s_recv_addr @@ -149,12 +151,19 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // send the write data to CTC when (state === s_w_body && io.flit.out.ready) { idx := idx + 1.U - when (idx === len) { + when (idx === nChunksPerBeat.U - 1.U) { idx := 0.U - state := s_recv_cmd + len := len - 1.U + state := Mux(len === 1.U, s_recv_cmd, s_w_req) } } + // receive a new write beat from TL + when (state === s_w_req && mem.a.ready) { + state := s_w_body + body := mem.a.bits.data.asTypeOf(body) + } + // send the write acknoledgement to TL when (state === s_w_ack && mem.d.ready) { state := s_idle From 7558fa550b8d3c2f541a217e8bebcdff8a5946a4 Mon Sep 17 00:00:00 2001 From: Lux Date: Mon, 7 Apr 2025 18:34:54 -0700 Subject: [PATCH 10/18] FIX: accomodate for spec changes --- src/main/scala/ctc/CTC.scala | 1 + src/main/scala/ctc/CTCToTileLink.scala | 12 ++++++------ src/main/scala/ctc/TileLinkToCTC.scala | 17 ++++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/scala/ctc/CTC.scala b/src/main/scala/ctc/CTC.scala index 582a5597..abae5be1 100644 --- a/src/main/scala/ctc/CTC.scala +++ b/src/main/scala/ctc/CTC.scala @@ -4,6 +4,7 @@ import chisel3._ object CTC { val INNER_WIDTH = 32 + val INNER_WIDTH_BYTES = INNER_WIDTH / 8 val OUTER_WIDTH = 4 } diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 249c5316..0033d93b 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -58,7 +58,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { val (s_cmd :: s_addr :: s_r_req :: s_r_data :: s_send_ack :: s_send_addr :: s_r_body :: s_w_body :: s_w_data :: s_w_wait :: Nil) = Enum(10) val state = RegInit(s_cmd) - val idx = Reg(UInt(log2Up(nChunksPerWord).W)) + val idx = Reg(UInt(log2Up(Math.max(nChunksPerBeat, nChunksPerWord)).W)) // state-driven signals io.flit.in.ready := state.isOneOf(s_cmd, s_addr, s_w_body) @@ -77,7 +77,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { mem.e.valid := false.B when (state === s_cmd && io.flit.in.valid) { - len := io.flit.in.bits.flit(lenLen - 1, 0) + len := io.flit.in.bits.flit(lenLen - 1, 0) + 1.U ctc_len := io.flit.in.bits.flit(lenLen - 1, 0) cmd := io.flit.in.bits.flit(cmdLen + lenLen - 1, lenLen) addr := 0.U @@ -130,10 +130,10 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // send the read data to outer CTC when (state === s_r_body && io.flit.out.ready) { idx := idx + 1.U + len := len - 1.U when (idx === (nChunksPerBeat - 1).U) { - len := len - 1.U tladdr := next_tl_addr - state := Mux(len === 0.U, s_cmd, s_r_req) // send next TL R Request + state := Mux(len === 1.U, s_cmd, s_r_req) // send next TL R Request } } // END: handling read requests @@ -156,12 +156,12 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // wait for write response from inner TL when (state === s_w_wait && mem.d.valid) { - when (len === 0.U) { + when (len === nChunksPerBeat.U) { // am I the last beat? state := s_send_ack } .otherwise { addr := addr + 1.U tladdr := next_tl_addr - len := len - 1.U + len := len - nChunksPerBeat.U idx := 0.U state := s_w_body } diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 79ac2aa7..e1e57665 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -48,7 +48,6 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val nChunksPerBeat = dataBits / CTC.INNER_WIDTH val byteAddrBits = log2Ceil(beatBytes) val nChunksPerWord = wordLen / CTC.INNER_WIDTH - val maxChunks = outer.maxBeats * nChunksPerBeat val len = Reg(UInt(lenLen.W)) val ctc_len = Reg(UInt(lenLen.W)) @@ -56,13 +55,13 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { dontTouch(lg_size) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) - val body = Reg(Vec(maxChunks, UInt(CTC.INNER_WIDTH.W))) + val body = Reg(Vec(nChunksPerBeat, UInt(CTC.INNER_WIDTH.W))) // ====== state machine ====== val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: s_r_body :: s_r_ack :: s_w_req :: s_w_body :: s_w_ack :: Nil) = Enum(10) val state = RegInit(s_idle) - val idx = Reg(UInt(log2Up(beatBytes).W)) + val idx = Reg(UInt(log2Up(Math.max(nChunksPerBeat, nChunksPerWord)).W)) // state-driven signals io.flit.in.ready := state.isOneOf(s_r_body, s_recv_cmd, s_recv_addr) @@ -72,7 +71,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) val tl_write_ack = edge.AccessAck(0.U, lg_size) - val tl_read_ack = edge.AccessAck(0.U, lg_size, body.asUInt) + val tl_read_ack = edge.AccessAck(0.U, lg_size, body(idx).asUInt) mem.a.ready := state.isOneOf(s_idle, s_w_req) mem.b.valid := false.B @@ -83,8 +82,8 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { when (state === s_idle && mem.a.valid) { - len := (1.U << mem.a.bits.size) / beatBytes.U - ctc_len := (1.U << mem.a.bits.size) / beatBytes.U + len := (1.U << mem.a.bits.size) / CTC.INNER_WIDTH_BYTES.U + ctc_len := (1.U << mem.a.bits.size) / CTC.INNER_WIDTH_BYTES.U lg_size := mem.a.bits.size cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) addr := mem.a.bits.address @@ -126,13 +125,13 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { } // BEGIN: handling read requests - // wait and collect the read response + // wait and collect the read response from CTC when (state === s_r_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.flit.asUInt idx := idx + 1.U + len := len - 1.U when (idx === nChunksPerBeat.U - 1.U) { state := s_r_ack - len := len - 1.U } } // send the read acknoledgement to TL @@ -151,9 +150,9 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // send the write data to CTC when (state === s_w_body && io.flit.out.ready) { idx := idx + 1.U + len := len - 1.U when (idx === nChunksPerBeat.U - 1.U) { idx := 0.U - len := len - 1.U state := Mux(len === 1.U, s_recv_cmd, s_w_req) } } From 7c2d993432d5c79fd58d7289c8bd183c7838618f Mon Sep 17 00:00:00 2001 From: Lux Date: Tue, 8 Apr 2025 10:26:51 -0700 Subject: [PATCH 11/18] ADD: min transfersize -> 1 --- src/main/scala/ctc/TileLinkToCTC.scala | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index e1e57665..a4f6f57d 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -21,8 +21,8 @@ class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = address = Seq(addrSet), regionType = RegionType.UNCACHED, supports = TLMasterToSlaveTransferSizes( - putFull = TransferSizes(beatBytes, beatBytes*maxBeats), // for now, only support single beat - get = TransferSizes(beatBytes, beatBytes*maxBeats) + putFull = TransferSizes(1, beatBytes*maxBeats), + get = TransferSizes(1, beatBytes*maxBeats) ), fifoId = Some(0))), // requests are handled in order beatBytes = beatBytes))) @@ -59,7 +59,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { // ====== state machine ====== val (s_idle :: s_send_cmd :: s_send_addr :: s_recv_cmd:: s_recv_addr :: - s_r_body :: s_r_ack :: s_w_req :: s_w_body :: s_w_ack :: Nil) = Enum(10) + s_r_body :: s_r_ack :: s_w_req :: s_w_body :: s_w_ack ::s_reject :: Nil) = Enum(11) val state = RegInit(s_idle) val idx = Reg(UInt(log2Up(Math.max(nChunksPerBeat, nChunksPerWord)).W)) @@ -87,11 +87,9 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { lg_size := mem.a.bits.size cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) addr := mem.a.bits.address - state := s_send_cmd + state := Mux(mem.a.bits.size >= 3.U, s_send_cmd, s_reject) idx := 0.U - when (cmd === CTCCommand.write_req) { - body := mem.a.bits.data.asTypeOf(body) - } + when (cmd === CTCCommand.write_req) { body := mem.a.bits.data.asTypeOf(body) } } when (state === s_send_cmd && io.flit.out.ready) { @@ -167,6 +165,12 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { when (state === s_w_ack && mem.d.ready) { state := s_idle } - // END: handling write requests + + // BEGIN: reject sub-word transactions + when (state === s_reject && mem.d.ready) { + // TODO: send reject to TL D channel + state := s_idle + } + // END: reject sub-word transactions } \ No newline at end of file From afed322d7e36fa5671b3a419333c4e9fe81d8c67 Mon Sep 17 00:00:00 2001 From: Lux Date: Wed, 9 Apr 2025 18:36:39 -0700 Subject: [PATCH 12/18] git commit -m "ADD: implement CTC parameters and integration with DigitalTop, including clock domain management and PHY interface" --trailer "Co-authored-by: -T.K.- " --- src/main/scala/ctc/CTC.scala | 118 ++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/src/main/scala/ctc/CTC.scala b/src/main/scala/ctc/CTC.scala index abae5be1..7cd7563f 100644 --- a/src/main/scala/ctc/CTC.scala +++ b/src/main/scala/ctc/CTC.scala @@ -1,6 +1,19 @@ package testchipip.ctc import chisel3._ +import chisel3.util._ +import chisel3.experimental.dataview._ + +import org.chipsalliance.cde.config.{Parameters, Field, Config} +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.util.ResetCatchAndSync +// import testchipip.soc.{SBUS} + +import testchipip.serdes._ + object CTC { val INNER_WIDTH = 32 @@ -13,4 +26,107 @@ object CTCCommand { val write_req = 1.U val read_ack = 2.U val write_ack = 3.U -} \ No newline at end of file +} + +case class CTCParams( + address: BigInt = 0x60000000, + managerBus: Option[TLBusWrapperLocation] = Some(SBUS), + clientBus: Option[TLBusWrapperLocation] = Some(SBUS), + phyFreqMHz: Int = 100 +) + +case object CTCKey extends Field[Option[CTCParams]](None) + +trait CanHavePeripheryCTC { this: BaseSubsystem => + private val portName = "ctc" + + val ctc_name = s"ctc" + val (ctc2tl, tl2ctc, outer_io) = p(CTCKey) match { + case Some(params) => { + + val phyParams = CreditedSourceSyncSerialPhyParams( + phitWidth = CTC.OUTER_WIDTH, + flitWidth = CTC.INNER_WIDTH, + freqMHz = params.phyFreqMHz, + flitBufferSz = 16 + ) + + lazy val slave_bus = locateTLBusWrapper(params.managerBus.get) + lazy val master_bus = locateTLBusWrapper(params.clientBus.get) + + val ctc_domain = LazyModule(new ClockSinkDomain(name=Some(s"CTC"))) + ctc_domain.clockNode := slave_bus.fixedClockNode + + require(slave_bus.dtsFrequency.isDefined, + s"Slave bus ${slave_bus.busName} must provide a frequency") + require(master_bus.dtsFrequency.isDefined, + s"Master bus ${master_bus.busName} must provide a frequency") + require(slave_bus.dtsFrequency == master_bus.dtsFrequency, + s"Mismatching slave freq ${slave_bus.dtsFrequency} != master freq ${master_bus.dtsFrequency}") + + + val ctc2tl = ctc_domain { LazyModule(new CTCToTileLink()(p)) } + val tl2ctc = ctc_domain { LazyModule(new TileLinkToCTC(baseAddr=0x60000000)(p)) } + + slave_bus.coupleTo(portName) { tl2ctc.node := TLBuffer() := _ } + master_bus.coupleFrom(portName) { _ := TLBuffer() := ctc2tl.node } + + // If we provide a clock, generate a clock domain for the outgoing clock + val serial_tl_clock_freqMHz = CreditedSourceSyncSerialPhyParams().freqMHz + val serial_tl_clock_node = ctc_domain { ClockSinkNode(Seq(ClockSinkParameters(take=Some(ClockParameters(serial_tl_clock_freqMHz))))) } + serial_tl_clock_node := ClockGroup()(p, ValName(s"${ctc_name}_clock")) := allClockGroupsNode + + val phit_io = ctc_domain { InModuleBody { + val phit_io = IO(phyParams.genIO).suggestName(ctc_name) + + // 3 clock domains - + // - ctc2tl's "Inner clock": synchronizes signals going to the digital logic + // - outgoing clock: synchronizes signals going out + // - incoming clock: synchronizes signals coming in + val outgoing_clock = serial_tl_clock_node.in.head._1.clock + val outgoing_reset = ResetCatchAndSync(outgoing_clock, ctc2tl.module.reset.asBool) + val incoming_clock = phit_io.clock_in + val incoming_reset = ResetCatchAndSync(incoming_clock, phit_io.reset_in.asBool) + phit_io.clock_out := outgoing_clock + phit_io.reset_out := outgoing_reset.asAsyncReset + val phy = Module(new CreditedSerialPhy(2, phyParams)) + phy.io.incoming_clock := incoming_clock + phy.io.incoming_reset := incoming_reset + phy.io.outgoing_clock := outgoing_clock + phy.io.outgoing_reset := outgoing_reset + phy.io.inner_clock := ctc2tl.module.clock + phy.io.inner_reset := ctc2tl.module.reset + phy.io.inner_ser(0) <> ctc2tl.module.io.flit + phy.io.inner_ser(1) <> tl2ctc.module.io.flit + + phy.io.outer_ser <> phit_io.viewAsSupertype(new ValidPhitIO(phyParams.phitWidth)) + phit_io + }} + + val outer_io = InModuleBody { + val outer_io = IO(phyParams.genIO).suggestName(ctc_name) + outer_io <> phit_io + outer_io + } + + // val inner_debug_io = ctc_domain { InModuleBody { + // val inner_debug_io = IO(new SerdesDebugIO).suggestName(s"${ctc_name}_debug") + // inner_debug_io := ctc2tl.module.io.debug + // inner_debug_io + // }} + // val outer_debug_io = InModuleBody { + // val outer_debug_io = IO(new SerdesDebugIO).suggestName(s"${ctc_name}_debug") + // outer_debug_io := inner_debug_io + // outer_debug_io + // } + + (ctc2tl, tl2ctc, outer_io) + } + case None => (None, None, None) + } +} + + +class WithCTC extends Config((site, here, up) => { + case CTCKey => Some(CTCParams()) +}) \ No newline at end of file From 0bc42f7b5ac30eecb55ba6033bb24cec9def8f2b Mon Sep 17 00:00:00 2001 From: Ella Schwarz Date: Mon, 28 Apr 2025 14:51:48 -0700 Subject: [PATCH 13/18] ADD: better params passing --- src/main/scala/ctc/CTC.scala | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/scala/ctc/CTC.scala b/src/main/scala/ctc/CTC.scala index 7cd7563f..286cda25 100644 --- a/src/main/scala/ctc/CTC.scala +++ b/src/main/scala/ctc/CTC.scala @@ -30,6 +30,7 @@ object CTCCommand { case class CTCParams( address: BigInt = 0x60000000, + size: BigInt = 1024, managerBus: Option[TLBusWrapperLocation] = Some(SBUS), clientBus: Option[TLBusWrapperLocation] = Some(SBUS), phyFreqMHz: Int = 100 @@ -41,7 +42,7 @@ trait CanHavePeripheryCTC { this: BaseSubsystem => private val portName = "ctc" val ctc_name = s"ctc" - val (ctc2tl, tl2ctc, outer_io) = p(CTCKey) match { + val (ctc2tl, tl2ctc, ctc_io) = p(CTCKey) match { case Some(params) => { val phyParams = CreditedSourceSyncSerialPhyParams( @@ -66,7 +67,7 @@ trait CanHavePeripheryCTC { this: BaseSubsystem => val ctc2tl = ctc_domain { LazyModule(new CTCToTileLink()(p)) } - val tl2ctc = ctc_domain { LazyModule(new TileLinkToCTC(baseAddr=0x60000000)(p)) } + val tl2ctc = ctc_domain { LazyModule(new TileLinkToCTC(baseAddr=params.address, size=params.size)(p)) } slave_bus.coupleTo(portName) { tl2ctc.node := TLBuffer() := _ } master_bus.coupleFrom(portName) { _ := TLBuffer() := ctc2tl.node } @@ -120,13 +121,13 @@ trait CanHavePeripheryCTC { this: BaseSubsystem => // outer_debug_io // } - (ctc2tl, tl2ctc, outer_io) + (ctc2tl, tl2ctc, Some(outer_io)) } case None => (None, None, None) } } -class WithCTC extends Config((site, here, up) => { - case CTCKey => Some(CTCParams()) +class WithCTC(params: CTCParams = CTCParams()) extends Config((site, here, up) => { + case CTCKey => Some(params) }) \ No newline at end of file From 447dec59107960c38c3e8d0d6b4d5b4e250f57a3 Mon Sep 17 00:00:00 2001 From: lux Date: Thu, 1 May 2025 00:37:27 -0700 Subject: [PATCH 14/18] ADD: support 4byte transactions --- src/main/scala/ctc/CTC.scala | 8 ++++++-- src/main/scala/ctc/CTCToTileLink.scala | 11 ++++++----- src/main/scala/ctc/TileLinkToCTC.scala | 19 +++++++++++-------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/main/scala/ctc/CTC.scala b/src/main/scala/ctc/CTC.scala index 286cda25..08b8ecc6 100644 --- a/src/main/scala/ctc/CTC.scala +++ b/src/main/scala/ctc/CTC.scala @@ -66,7 +66,9 @@ trait CanHavePeripheryCTC { this: BaseSubsystem => s"Mismatching slave freq ${slave_bus.dtsFrequency} != master freq ${master_bus.dtsFrequency}") + // slave val ctc2tl = ctc_domain { LazyModule(new CTCToTileLink()(p)) } + // master val tl2ctc = ctc_domain { LazyModule(new TileLinkToCTC(baseAddr=params.address, size=params.size)(p)) } slave_bus.coupleTo(portName) { tl2ctc.node := TLBuffer() := _ } @@ -97,8 +99,10 @@ trait CanHavePeripheryCTC { this: BaseSubsystem => phy.io.outgoing_reset := outgoing_reset phy.io.inner_clock := ctc2tl.module.clock phy.io.inner_reset := ctc2tl.module.reset - phy.io.inner_ser(0) <> ctc2tl.module.io.flit - phy.io.inner_ser(1) <> tl2ctc.module.io.flit + phy.io.inner_ser(0).in <> ctc2tl.module.io.flit.in + phy.io.inner_ser(0).out <> tl2ctc.module.io.flit.out + phy.io.inner_ser(1).in <> tl2ctc.module.io.flit.in + phy.io.inner_ser(1).out <> ctc2tl.module.io.flit.out phy.io.outer_ser <> phit_io.viewAsSupertype(new ValidPhitIO(phyParams.phitWidth)) phit_io diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 0033d93b..7eb1a81d 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -84,6 +84,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { idx := 0.U ack := false.B state := s_addr + body.foreach(_ := 0.U) } when (state === s_addr && io.flit.in.valid) { @@ -131,7 +132,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { when (state === s_r_body && io.flit.out.ready) { idx := idx + 1.U len := len - 1.U - when (idx === (nChunksPerBeat - 1).U) { + when (idx === (nChunksPerBeat - 1).U || len === 1.U) { tladdr := next_tl_addr state := Mux(len === 1.U, s_cmd, s_r_req) // send next TL R Request } @@ -142,7 +143,8 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // collect the write data from the CTC when (state === s_w_body && io.flit.in.valid) { body(idx) := io.flit.in.bits.asUInt - when (idx === (nChunksPerBeat - 1).U) { + len := len - 1.U + when (idx === (nChunksPerBeat - 1).U || len === 1.U) { state := s_w_data } .otherwise { idx := idx + 1.U @@ -156,12 +158,11 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { // wait for write response from inner TL when (state === s_w_wait && mem.d.valid) { - when (len === nChunksPerBeat.U) { // am I the last beat? + when (len === 0.U) { // am I the last beat? state := s_send_ack } .otherwise { - addr := addr + 1.U + // addr := addr + 1.U tladdr := next_tl_addr - len := len - nChunksPerBeat.U idx := 0.U state := s_w_body } diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index a4f6f57d..f7206160 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -51,8 +51,9 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { val len = Reg(UInt(lenLen.W)) val ctc_len = Reg(UInt(lenLen.W)) - val lg_size = Reg(UInt(log2Ceil(beatBytes * outer.maxBeats).W)) - dontTouch(lg_size) + val a_lg_size = Reg(UInt(log2Ceil(beatBytes * outer.maxBeats).W)) + val a_source = Reg(UInt(edge.bundle.sourceBits.W)) + dontTouch(a_lg_size) val cmd = Reg(UInt(cmdLen.W)) val addr = Reg(UInt(wordLen.W)) val body = Reg(Vec(nChunksPerBeat, UInt(CTC.INNER_WIDTH.W))) @@ -70,8 +71,8 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { Mux(state === s_send_addr, addr(CTC.INNER_WIDTH - 1, 0), body(idx))) io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) - val tl_write_ack = edge.AccessAck(0.U, lg_size) - val tl_read_ack = edge.AccessAck(0.U, lg_size, body(idx).asUInt) + val tl_write_ack = edge.AccessAck(a_source, a_lg_size) + val tl_read_ack = edge.AccessAck(a_source, a_lg_size, body(idx).asUInt) mem.a.ready := state.isOneOf(s_idle, s_w_req) mem.b.valid := false.B @@ -84,10 +85,12 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { when (state === s_idle && mem.a.valid) { len := (1.U << mem.a.bits.size) / CTC.INNER_WIDTH_BYTES.U ctc_len := (1.U << mem.a.bits.size) / CTC.INNER_WIDTH_BYTES.U - lg_size := mem.a.bits.size + a_lg_size := mem.a.bits.size + a_source := mem.a.bits.source cmd := Mux(mem.a.bits.opcode === TLMessages.Get, CTCCommand.read_req, CTCCommand.write_req) addr := mem.a.bits.address - state := Mux(mem.a.bits.size >= 3.U, s_send_cmd, s_reject) + state := Mux(mem.a.bits.size >= 2.U, s_send_cmd, s_reject) + // state := s_send_cmd idx := 0.U when (cmd === CTCCommand.write_req) { body := mem.a.bits.data.asTypeOf(body) } } @@ -128,7 +131,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { body(idx) := io.flit.in.bits.flit.asUInt idx := idx + 1.U len := len - 1.U - when (idx === nChunksPerBeat.U - 1.U) { + when (idx === nChunksPerBeat.U - 1.U || len === 1.U) { state := s_r_ack } } @@ -149,7 +152,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { when (state === s_w_body && io.flit.out.ready) { idx := idx + 1.U len := len - 1.U - when (idx === nChunksPerBeat.U - 1.U) { + when (idx === nChunksPerBeat.U - 1.U || len === 1.U) { idx := 0.U state := Mux(len === 1.U, s_recv_cmd, s_w_req) } From fb7dd71839de2e104926d10b5fd8b34d1d39b0d6 Mon Sep 17 00:00:00 2001 From: lux Date: Thu, 1 May 2025 01:10:57 -0700 Subject: [PATCH 15/18] ADD: fix content --- src/main/scala/ctc/TileLinkToCTC.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index f7206160..1e92fad4 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -72,7 +72,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { io.flit.out.bits := out_bits.asTypeOf(io.flit.out.bits) val tl_write_ack = edge.AccessAck(a_source, a_lg_size) - val tl_read_ack = edge.AccessAck(a_source, a_lg_size, body(idx).asUInt) + val tl_read_ack = edge.AccessAck(a_source, a_lg_size, body.asUInt) mem.a.ready := state.isOneOf(s_idle, s_w_req) mem.b.valid := false.B @@ -92,6 +92,7 @@ class TileLinkToCTCModule(outer: TileLinkToCTC) extends LazyModuleImp(outer) { state := Mux(mem.a.bits.size >= 2.U, s_send_cmd, s_reject) // state := s_send_cmd idx := 0.U + body := mem.a.bits.data.asTypeOf(body) when (cmd === CTCCommand.write_req) { body := mem.a.bits.data.asTypeOf(body) } } From f8b2f0ad88354eadc7dbfedf67f5f74213bb564f Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Sun, 6 Apr 2025 02:57:32 -0700 Subject: [PATCH 16/18] add LazyModule for address translation --- src/main/scala/soc/OffchipBus.scala | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/scala/soc/OffchipBus.scala b/src/main/scala/soc/OffchipBus.scala index 0ec18d69..afb45afa 100644 --- a/src/main/scala/soc/OffchipBus.scala +++ b/src/main/scala/soc/OffchipBus.scala @@ -94,3 +94,33 @@ trait CanHaveSwitchableOffchipBus { this: BaseSubsystem => }) } } + +/* + * This series of TL widgets works to map the innate + * address range of a given node to another address range. + * Consequent to whatever bus this unit is attached, + * the diplomatic node is address by new new address region + * + * Exact operation is node's address + base, region size is maintained + */ +case class InwardAddressTranslator(blockRange : AddressSet, replicationBase : Option[BigInt] = None)(implicit p: Parameters) extends LazyModule { + val module_side = replicationBase.map { base => + val baseRegion = AddressSet(0, base-1) + val replicator = LazyModule(new RegionReplicator(ReplicatedRegion(baseRegion, baseRegion.widen(base)))) + val prefixSource = BundleBridgeSource[UInt](() => UInt(1.W)) + replicator.prefix := prefixSource + InModuleBody { prefixSource.bundle := 0.U(1.W) } // prefix is unused for TL uncached, so this is ok + replicator.node + }.getOrElse { TLTempNode() } + + // val bus_side = TLFilter(TLFilter.mSelectIntersect(blockRange))(p) + val bus_side = TLFilter(TLFilter.mSubtract(blockRange))(p) + + // module_side := bus_side + + def apply(node : TLNode) : TLNode = { + node := module_side := bus_side + } + + lazy val module = new LazyModuleImp(this) {} +} From 14be8b246fd8eb3456ee02e183c01a3e8ed28885 Mon Sep 17 00:00:00 2001 From: Ella Schwarz Date: Wed, 7 May 2025 16:33:09 -0700 Subject: [PATCH 17/18] Add address translation unit --- src/main/scala/ctc/CTC.scala | 14 ++++++++++---- src/main/scala/ctc/TileLinkToCTC.scala | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/scala/ctc/CTC.scala b/src/main/scala/ctc/CTC.scala index 08b8ecc6..bdcc3356 100644 --- a/src/main/scala/ctc/CTC.scala +++ b/src/main/scala/ctc/CTC.scala @@ -13,6 +13,7 @@ import freechips.rocketchip.util.ResetCatchAndSync // import testchipip.soc.{SBUS} import testchipip.serdes._ +import testchipip.soc.{InwardAddressTranslator} object CTC { @@ -29,8 +30,9 @@ object CTCCommand { } case class CTCParams( - address: BigInt = 0x60000000, - size: BigInt = 1024, + onchipAddr: BigInt = 0x100000000L, // addresses that get routed here from THIS chip + offchipAddr: BigInt = 0x0, // addresses that this ctc device can access on the OTHER chip + size: BigInt = ((1L << 10) - 1), // 1024 bytes managerBus: Option[TLBusWrapperLocation] = Some(SBUS), clientBus: Option[TLBusWrapperLocation] = Some(SBUS), phyFreqMHz: Int = 100 @@ -69,9 +71,13 @@ trait CanHavePeripheryCTC { this: BaseSubsystem => // slave val ctc2tl = ctc_domain { LazyModule(new CTCToTileLink()(p)) } // master - val tl2ctc = ctc_domain { LazyModule(new TileLinkToCTC(baseAddr=params.address, size=params.size)(p)) } + val tl2ctc = ctc_domain { LazyModule(new TileLinkToCTC(baseAddr=params.offchipAddr, size=params.size)(p)) } - slave_bus.coupleTo(portName) { tl2ctc.node := TLBuffer() := _ } + val translator = ctc_domain { + LazyModule(InwardAddressTranslator(AddressSet(params.offchipAddr, params.size), Some(params.onchipAddr))(p)) + } + + slave_bus.coupleTo(portName) { translator(tl2ctc.node) := TLBuffer() := _ } master_bus.coupleFrom(portName) { _ := TLBuffer() := ctc2tl.node } // If we provide a clock, generate a clock domain for the outgoing clock diff --git a/src/main/scala/ctc/TileLinkToCTC.scala b/src/main/scala/ctc/TileLinkToCTC.scala index 1e92fad4..768a5f97 100644 --- a/src/main/scala/ctc/TileLinkToCTC.scala +++ b/src/main/scala/ctc/TileLinkToCTC.scala @@ -13,9 +13,9 @@ import org.chipsalliance.cde.config.{Parameters, Field} // to outer: sends read and write requests in CTC // from outer: receives read and write responses in CTC // to inner: sends read and write responses in TL -class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = 1024, val maxBeats: Int = 4) +class TileLinkToCTC(sinkIds: Int = 1, val beatBytes: Int = 8, baseAddr: BigInt = 0, size: BigInt = ((1L << 10) - 1), val maxBeats: Int = 4) (implicit p: Parameters) extends LazyModule { - val addrSet = AddressSet(baseAddr, size - 1) + val addrSet = AddressSet(baseAddr, size) val node = TLManagerNode(Seq(TLSlavePortParameters.v1( managers = Seq(TLSlaveParameters.v2( address = Seq(addrSet), From a336cb275d284c36d22237d6a3b489331443b714 Mon Sep 17 00:00:00 2001 From: lux Date: Wed, 7 May 2025 18:27:24 -0700 Subject: [PATCH 18/18] ADD: fix for address mismatch --- src/main/scala/ctc/CTCToTileLink.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/ctc/CTCToTileLink.scala b/src/main/scala/ctc/CTCToTileLink.scala index 7eb1a81d..15dc4062 100644 --- a/src/main/scala/ctc/CTCToTileLink.scala +++ b/src/main/scala/ctc/CTCToTileLink.scala @@ -93,7 +93,7 @@ class CTCToTileLinkModule(outer: CTCToTileLink) extends LazyModuleImp(outer) { idx := idx + 1.U when (idx === (nChunksPerWord - 1).U) { idx := 0.U - tladdr := addr + tladdr := addr | (io.flit.in.bits.flit << (idx * CTC.INNER_WIDTH.U)) when (cmd === CTCCommand.read_req) { state := s_r_req } .elsewhen (cmd === CTCCommand.write_req) {