# 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
#
#     https://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.

import cocotb
from cocotb.clock import Clock
from cocotb.triggers import FallingEdge, RisingEdge, ClockCycles, with_timeout
import random

from kelvin_test_utils.TileLinkULInterface import TileLinkULInterface, create_a_channel_req


async def setup_dut(dut):
    """Common setup for all tests."""
    clock = Clock(dut.clock, 10)
    cocotb.start_soon(clock.start())
    dut.reset.value = 1
    await ClockCycles(dut.clock, 2)
    dut.reset.value = 0
    await RisingEdge(dut.clock)


@cocotb.test()
async def test_steering(dut):
    """Verify requests are steered to the correct device port."""
    await setup_dut(dut)

    N = 4  # This is hardcoded in the Chisel emitter for now
    host_if = TileLinkULInterface(dut, host_if_name="io_tl_h")
    device_ifs = [
        TileLinkULInterface(dut, device_if_name=f"io_tl_d_{i}")
        for i in range(N)
    ]

    async def device_responder(device_if, i):
        req_seen = await device_if.device_get_request()
        await device_if.device_respond(opcode=0,
                                       param=0,
                                       size=req_seen["size"],
                                       source=req_seen["source"])

    # Start all device responders
    for i in range(N):
        cocotb.start_soon(device_responder(device_ifs[i], i))

    for i in range(N):
        dut.io_dev_select_i.value = i
        req = create_a_channel_req(address=0x1000 + i * 0x100,
                                   data=0x11223344 + i,
                                   mask=0xF,
                                   source=i)

        await host_if.host_put(req)
        response = await host_if.host_get_response()

        assert response["source"] == i
        # TODO(atv): Can we do this better?
        # Allow some time for the device responder to process the request
        await ClockCycles(dut.clock, 5)


@cocotb.test()
async def test_error_response(dut):
    """Verify error response for out-of-bounds dev_select."""
    await setup_dut(dut)

    N = 4  # This is hardcoded in the Chisel emitter for now
    host_if = TileLinkULInterface(dut, host_if_name="io_tl_h")

    # dev_select_i is NWD bits wide, where NWD = ceil(log2(N+1))
    # So, a value of N should be out of bounds and trigger an error
    dut.io_dev_select_i.value = N
    req = create_a_channel_req(address=0xBAD,
                               data=0xBAD,
                               mask=0xF,
                               source=(1 << 6) - 1)

    await host_if.host_put(req)
    response = await host_if.host_get_response()

    assert response["error"] == 1
    assert response["source"] == req["source"]
