// Copyright 2025 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 common.KelvinRRArbiter
import _root_.circt.stage.{ChiselStage,FirtoolOption}
import chisel3.stage.ChiselGeneratorAnnotation
import scala.annotation.nowarn

/**
  * TLUL2Axi: A Chisel module that serves as a bridge between a TileLink-UL master
  * and an AXI4 slave.
  *
  * This module translates TileLink Get and Put operations into AXI read and write
  * transactions, respectively. It uses a dataflow approach with queues and an
  * arbiter to manage the protocol conversion.
  *
  * @param p The Kelvin parameters.
  */
class TLUL2Axi[A_USER <: Data, D_USER <: Data](p: Parameters, userAGen: () => A_USER, userDGen: () => D_USER) extends Module {
  val tlul_p = new TLULParameters(p)
  val io = IO(new Bundle {
    val tl_a = Flipped(Decoupled(new TileLink_A_ChannelBase(tlul_p, userAGen))) // TileLink Input
    val tl_d = Decoupled(new TileLink_D_ChannelBase(tlul_p, userDGen))          // TileLink Output
    val axi = new AxiMasterIO(p.axi2AddrBits, p.axi2DataBits, p.axi2IdBits)
  })
  // --- Queue for incoming TileLink A-Channel requests ---
  val tl_a_q = Queue(io.tl_a, 2)

  val is_get = tl_a_q.bits.opcode === TLULOpcodesA.Get.asUInt
  val is_put = tl_a_q.bits.opcode === TLULOpcodesA.PutFullData.asUInt ||
               tl_a_q.bits.opcode === TLULOpcodesA.PutPartialData.asUInt

  // --- AXI Channel Generation ---
  // TODO: Consider gating these signals (on get/put)? Especially address.
  // Drive AXI write channels for Put requests
  val aw_q = Module(new Queue(new AxiAddress(p.axi2AddrBits, p.axi2DataBits, p.axi2IdBits), 1))
  aw_q.io.enq.valid := tl_a_q.valid && is_put
  aw_q.io.enq.bits.addr := tl_a_q.bits.address
  aw_q.io.enq.bits.id := tl_a_q.bits.source
  aw_q.io.enq.bits.len := 0.U
  aw_q.io.enq.bits.size := tl_a_q.bits.size
  aw_q.io.enq.bits.burst := AxiBurstType.INCR.asUInt
  aw_q.io.enq.bits.prot := 0.U
  aw_q.io.enq.bits.lock := 0.U
  aw_q.io.enq.bits.cache := 0.U
  aw_q.io.enq.bits.qos := 0.U
  aw_q.io.enq.bits.region := 0.U

  val w_q = Module(new Queue(new AxiWriteData(p.axi2DataBits, p.axi2IdBits), 1))
  w_q.io.enq.valid := tl_a_q.valid && is_put
  w_q.io.enq.bits.data := tl_a_q.bits.data
  w_q.io.enq.bits.strb := tl_a_q.bits.mask
  w_q.io.enq.bits.last := true.B

  io.axi.write.addr <> aw_q.io.deq
  io.axi.write.data <> w_q.io.deq

  // Drive AXI read channel for Get requests
  io.axi.read.addr.valid := tl_a_q.valid && is_get
  io.axi.read.addr.bits.addr := tl_a_q.bits.address
  io.axi.read.addr.bits.id   := tl_a_q.bits.source
  io.axi.read.addr.bits.len  := 0.U // No bursting
  io.axi.read.addr.bits.size := tl_a_q.bits.size
  io.axi.read.addr.bits.burst := AxiBurstType.INCR.asUInt // Doesn't matter
  io.axi.read.addr.bits.prot := 0.U // Default protection

  // Dequeue from TileLink queue when AXI transaction is accepted
  tl_a_q.ready := (is_get && io.axi.read.addr.ready) || (is_put && aw_q.io.enq.ready && w_q.io.enq.ready)

  io.axi.write.addr.bits.lock := 0.U
  io.axi.write.addr.bits.cache := 0.U
  io.axi.write.addr.bits.qos := 0.U
  io.axi.write.addr.bits.region := 0.U
  io.axi.read.addr.bits.lock := 0.U
  io.axi.read.addr.bits.cache := 0.U
  io.axi.read.addr.bits.qos := 0.U
  io.axi.read.addr.bits.region := 0.U

  // --- Response Path ---
  class TxInfo extends Bundle {
    val source = UInt(tlul_p.o.W)
    val size = UInt(tlul_p.z.W)
  }

  val read_tx_info_q = Module(new Queue(new TxInfo, entries = 2))
  val write_tx_info_q = Module(new Queue(new TxInfo, entries = 2))

  read_tx_info_q.io.enq.valid := tl_a_q.valid && is_get && io.axi.read.addr.ready
  read_tx_info_q.io.enq.bits.source := tl_a_q.bits.source
  read_tx_info_q.io.enq.bits.size := tl_a_q.bits.size

  write_tx_info_q.io.enq.valid := tl_a_q.valid && is_put && aw_q.io.enq.ready && w_q.io.enq.ready
  write_tx_info_q.io.enq.bits.source := tl_a_q.bits.source
  write_tx_info_q.io.enq.bits.size := tl_a_q.bits.size

  // --- TileLink D-Channel (Response) Generation ---
  val read_response = Wire(Decoupled(new TileLink_D_ChannelBase(tlul_p, userDGen)))
  val write_response = Wire(Decoupled(new TileLink_D_ChannelBase(tlul_p, userDGen)))

  // AXI Read Response -> TileLink AccessAckData
  read_response.valid := io.axi.read.data.valid && read_tx_info_q.io.deq.valid
  read_response.bits.opcode := TLULOpcodesD.AccessAckData.asUInt
  read_response.bits.param := 0.U
  read_response.bits.size := read_tx_info_q.io.deq.bits.size
  read_response.bits.source := read_tx_info_q.io.deq.bits.source
  read_response.bits.sink := 0.U
  read_response.bits.data := io.axi.read.data.bits.data
  read_response.bits.error := io.axi.read.data.bits.resp =/= 0.U
  read_response.bits.user := 0.U.asTypeOf(read_response.bits.user)

  // AXI Write Response -> TileLink AccessAck
  write_response.valid := io.axi.write.resp.valid && write_tx_info_q.io.deq.valid
  write_response.bits.opcode := TLULOpcodesD.AccessAck.asUInt
  write_response.bits.param := 0.U
  write_response.bits.size := write_tx_info_q.io.deq.bits.size
  write_response.bits.source := write_tx_info_q.io.deq.bits.source
  write_response.bits.sink := 0.U
  write_response.bits.data := 0.U
  write_response.bits.error := io.axi.write.resp.bits.resp =/= 0.U
  write_response.bits.user := 0.U.asTypeOf(write_response.bits.user)

  // Arbitrate between read and write responses for the D-channel
  val d_channel_arb = Module(new KelvinRRArbiter(new TileLink_D_ChannelBase(tlul_p, userDGen), 2))
  d_channel_arb.io.in(0) <> read_response
  d_channel_arb.io.in(1) <> write_response
  io.tl_d <> Queue(d_channel_arb.io.out, 2)

  // Drive ready signals
  io.axi.read.data.ready := d_channel_arb.io.in(0).ready
  read_tx_info_q.io.deq.ready := d_channel_arb.io.in(0).ready && io.axi.read.data.valid

  io.axi.write.resp.ready := d_channel_arb.io.in(1).ready
  write_tx_info_q.io.deq.ready := d_channel_arb.io.in(1).ready && io.axi.write.resp.valid

}

@nowarn
object EmitTLUL2Axi extends App {
  val p = Parameters()
  (new ChiselStage).execute(
    Array("--target", "systemverilog") ++ args,
    Seq(ChiselGeneratorAnnotation(() => new TLUL2Axi(p, () => new OpenTitanTileLink_A_User, () => new OpenTitanTileLink_D_User))) ++ Seq(FirtoolOption("-enable-layers=Verification"))
  )
}