| // Copyright 2024 Google LLC | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package bus | 
 |  | 
 | import chisel3._ | 
 | import chisel3.util._ | 
 |  | 
 | import kelvin.Parameters | 
 | import kelvin.MemoryRegion | 
 |  | 
 | class TLULParameters(p: Parameters) { | 
 |   val w = p.axi2DataBits / 8 | 
 |   val a = p.axi2AddrBits | 
 |   val z = log2Ceil(w) | 
 |   val o = p.axi2IdBits | 
 |   val i = 1 | 
 | } | 
 |  | 
 | object TLULOpcodesA extends ChiselEnum { | 
 |   val PutFullData = Value(0.U(3.W)) | 
 |   val PutPartialData = Value(1.U(3.W)) | 
 |   val Get = Value(4.U(3.W)) | 
 |   val End = Value(7.U(3.W)) | 
 | } | 
 |  | 
 | object TLULOpcodesD extends ChiselEnum { | 
 |   val AccessAck = Value(0.U(3.W)) | 
 |   val AccessAckData = Value(1.U(3.W)) | 
 |   val End = Value(7.U(3.W)) | 
 | } | 
 |  | 
 | class OpenTitanTileLink_A_User extends Bundle { | 
 |   val rsvd = UInt(5.W) | 
 |   val instr_type = UInt(4.W) // mubi4_t | 
 |   val cmd_intg = UInt(7.W) | 
 |   val data_intg = UInt(7.W) | 
 | } | 
 |  | 
 | class OpenTitanTileLink_D_User extends Bundle { | 
 |   val rsp_intg = UInt(7.W) | 
 |   val data_intg = UInt(7.W) | 
 | } | 
 |  | 
 | class NoUser extends Bundle {} | 
 |  | 
 | class TileLink_A_ChannelBase[T <: Data](p: TLULParameters, val userGen: () => T) extends Bundle { | 
 |   val opcode = UInt(3.W) | 
 |   val param = UInt(3.W) | 
 |   val size = UInt(p.z.W) | 
 |   val source = UInt(p.o.W) | 
 |   val address = UInt(p.a.W) | 
 |   val mask = UInt(p.w.W) | 
 |   val data = UInt((8 * p.w).W) | 
 |   val user = userGen() | 
 | } | 
 |  | 
 | class TileLink_D_ChannelBase[T <: Data](p: TLULParameters, val userGen: () => T) extends Bundle { | 
 |   val opcode = UInt(3.W) | 
 |   val param = UInt(3.W) | 
 |   val size = UInt(p.z.W) | 
 |   val source = UInt(p.o.W) | 
 |   val sink = UInt(p.i.W) | 
 |   val data = UInt((8 * p.w).W) | 
 |   val user = userGen() | 
 |   val error = Bool() | 
 | } | 
 |  | 
 | class TileLink_A_Channel(p: TLULParameters) extends TileLink_A_ChannelBase(p, () => new NoUser) {} | 
 | class TileLink_D_Channel(p: TLULParameters) extends TileLink_D_ChannelBase(p, () => new NoUser) {} | 
 |  | 
 | class TLULHost2Device[A_USER <: Data, D_USER <: Data](p: TLULParameters, userAGen: () => A_USER, userDGen: () => D_USER) extends Bundle { | 
 |   val a = Decoupled(new TileLink_A_ChannelBase(p, userAGen)) | 
 |   val d = Flipped(Decoupled(new TileLink_D_ChannelBase(p, userDGen))) | 
 | } | 
 |  | 
 | class TLULDevice2Host[A_USER <: Data, D_USER <: Data](p: TLULParameters, userAGen: () => A_USER, userDGen: () => D_USER) extends Bundle { | 
 |   val a = Flipped(Decoupled(new TileLink_A_ChannelBase(p, userAGen))) | 
 |   val d = Decoupled(new TileLink_D_ChannelBase(p, userDGen)) | 
 | } | 
 |  | 
 | object OpenTitanTileLink { | 
 |   class A_Channel(p: TLULParameters) extends TileLink_A_ChannelBase(p, () => new OpenTitanTileLink_A_User) {} | 
 |   class D_Channel(p: TLULParameters) extends TileLink_D_ChannelBase(p, () => new OpenTitanTileLink_D_User) {} | 
 |   class Host2Device(p: TLULParameters) extends TLULHost2Device(p, () => new OpenTitanTileLink_A_User, () => new OpenTitanTileLink_D_User) {} | 
 |   class Device2Host(p: TLULParameters) extends TLULDevice2Host(p, () => new OpenTitanTileLink_A_User, () => new OpenTitanTileLink_D_User) {} | 
 | } | 
 |  | 
 | // NB: Stuff below here is for ChAI -- it's not likely that you want | 
 | // to use these for new development. | 
 | class TileLinkULIO_H2D(p: TLULParameters) extends Bundle { | 
 |   val a_valid = (Bool()) | 
 |   val a_opcode = (UInt(3.W)) | 
 |   val a_param = (UInt(3.W)) | 
 |   val a_size = (UInt(p.z.W)) | 
 |   val a_source = (UInt(p.o.W)) | 
 |   val a_address = (UInt(p.a.W)) | 
 |   val a_mask = (UInt(p.w.W)) | 
 |   val a_data = (UInt((8 * p.w).W)) | 
 |   val a_user = new Bundle { | 
 |     val rsvd = UInt(5.W) | 
 |     val instr_type = UInt(4.W) // mubi4_t | 
 |     val cmd_intg = UInt(7.W) | 
 |     val data_intg = UInt(7.W) | 
 |   } | 
 |   val d_ready = (Bool()) | 
 | } | 
 |  | 
 | class TileLinkULIO_D2H(p: TLULParameters) extends Bundle { | 
 |   val d_valid = (Bool()) | 
 |   val d_opcode = (UInt(3.W)) | 
 |   val d_param = (UInt(3.W)) | 
 |   val d_size = (UInt(p.z.W)) | 
 |   val d_source = (UInt(p.o.W)) | 
 |   val d_sink = (UInt(p.i.W)) | 
 |   val d_data = (UInt((8 * p.w).W)) | 
 |   val d_user = new Bundle { | 
 |     val rsp_intg = UInt(7.W) | 
 |     val data_intg = UInt(7.W) | 
 |   } | 
 |   val d_error = (Bool()) | 
 |   val a_ready = (Bool()) | 
 | } | 
 |  | 
 | class TileLinkUL(p: TLULParameters, m: Seq[MemoryRegion], hosts: Int) extends Module { | 
 |   val devices = m.length | 
 |   val io = IO(new Bundle { | 
 |     val hosts_a = Vec(hosts, Input(new TileLinkULIO_H2D(p))) | 
 |     val hosts_d = Vec(hosts, Output(new TileLinkULIO_D2H(p))) | 
 |     val devices_a = Vec(devices, Output(new TileLinkULIO_H2D(p))) | 
 |     val devices_d = Vec(devices, Input(new TileLinkULIO_D2H(p))) | 
 |   }) | 
 |  | 
 |  | 
 |   for (i <- 0 until hosts) { | 
 |     io.hosts_d(i) := 0.U.asTypeOf(new TileLinkULIO_D2H(p)) | 
 |   } | 
 |   for (i <- 0 until devices) { | 
 |     io.devices_a(i) := 0.U.asTypeOf(new TileLinkULIO_H2D(p)) | 
 |   } | 
 |  | 
 |   val aValids = io.hosts_a.map(x => x.a_valid) | 
 |   val anyAValid = PopCount(aValids) > 0.U | 
 |   when(anyAValid) { | 
 |     val aValidIndex = PriorityEncoder(aValids) | 
 |     val host_a = io.hosts_a(aValidIndex) | 
 |     val host_d = io.hosts_d(aValidIndex) | 
 |     val address = host_a.a_address | 
 |  | 
 |     val addressOk = (0 until devices).map(x => m(x).contains(address)) | 
 |     val startAddresses = VecInit(m.map(x => x.memStart.U(p.a.W))) | 
 |     assert(PopCount(addressOk) === 1.U) | 
 |     val deviceIndex = PriorityEncoder(addressOk) | 
 |     val device_a = io.devices_a(deviceIndex) | 
 |     val device_d = io.devices_d(deviceIndex) | 
 |  | 
 |     device_a :<>= host_a | 
 |     device_a.a_address := host_a.a_address - startAddresses(deviceIndex) | 
 |     host_d :<>= device_d | 
 |   } | 
 |  | 
 |   val dValids = io.devices_d.map(x => x.d_valid) | 
 |   val anyDValid = dValids.reduce(_ || _) | 
 |   when(anyDValid) { | 
 |     val dValidIndex = PriorityEncoder(dValids) | 
 |     val device_d = io.devices_d(dValidIndex) | 
 |     val device_a = io.devices_a(dValidIndex) | 
 |     val source = device_d.d_source | 
 |     val host_d = io.hosts_d(source) | 
 |     val host_a = io.hosts_a(source) | 
 |  | 
 |     host_d :<>= device_d | 
 |     device_a :<>= host_a | 
 |   } | 
 | } |