UVM agent topology for request and response interfaces

I have a UVM agent which needs to drive request xtxns to DUT. The DUT returns request_credit to the agent. After a while, the DUT returns a response xtxn for the previous request. I need to grab it in my monitor, and send a response credit back to the DUT from the agent.

In your opinion, what is a good way to structure this?

Option 1 : Request and response are done through two different UVM agents, each having their own driver/seqr/monitor. A virtual sequence (or some other method) communicates between them if at all needed (like, tracking outstanding responses, so that no more requests are sent etc)

Option 2. Have one agent, which has one monitor grabbing all request and response signals. There are two drivers (with corresponding sequencers). One driver drives response credit back, the other drives requests.

Option 3. Have one agent as above, one monitor, but only one driver. There are two sequencers for the resp_credit and req_xtxns. The drivers have virtual interface handles for both interfaces, and gets stuff from the two sequencers in parallel, and drives them on corresponding interfaces (using an extra analysis_port and a fork-join method within run_phase)

In reply to 1978bubun:

I’m not sure if I understood your explanation correctly. But it looks like you have a piplelined bahavior, have you?

In reply to chr_sue:

In reply to 1978bubun:
I’m not sure if I understood your explanation correctly. But it looks like you have a piplelined bahavior, have you?

I wouldn’t call it a pipelined behavior. My request and response transactions are all single flit. There is no header-data separation.

In reply to 1978bubun:

The standard UVM behavior is that to aeach request there belongs a response. After the response was send back the next request will be generated. Is this the case in your example?