File: ctrlport_bfm_pkg.sv

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (238 lines) | stat: -rw-r--r-- 7,063 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//
// Copyright 2024 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Package: ctrlport_bfm_pkg
//
// Description:
//
//   Package defining a Control Port bus functional model (BFM).
//   See the RFNoC Specification for a protocol description.
//

package ctrlport_bfm_pkg;

  import ctrlport_pkg::*;

  class ctrlport_bfm;

    // create combined request and response struct for mailbox
    typedef struct {
      ctrlport_request_t req;
      ctrlport_response_t resp;
      bit skip_data_check;
    } ctrlport_transfer_t;

    local mailbox #(ctrlport_transfer_t) transactions;

    // link to interface
    local virtual ctrlport_if iface;

    // data copy for response data
    local logic [CTRLPORT_DATA_W-1:0] reponse_data;

    // ------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------
    // Class constructor. This must be given an interface for the master
    // connection and an interface for the slave connection.
    function new(virtual ctrlport_if iface);
      this.iface = iface;
      transactions = new;
    endfunction

    // ------------------------------------------------------------------
    // Asynchronous transaction handling
    // ------------------------------------------------------------------
    // Queue an asynchronous transaction (read or write with full request)
    task async_request(
      ctrlport_request_t request,
      ctrlport_response_t expected_response,
      bit skip_data_check = '0
    );
      assert (request.rd || request.wr) else
        $error("Transaction must be read or write");
      transactions.put('{request, expected_response, skip_data_check});
    endtask

    // Queue a simple write transaction
    task async_write(
      logic[CTRLPORT_ADDR_W-1:0] addr,
      logic[CTRLPORT_DATA_W-1:0] data,
      ctrlport_status_t expected_status = STS_OKAY
    );
      ctrlport_request_t request;
      ctrlport_response_t response;

      request = '0;
      request.wr = '1;
      request.addr = addr;
      request.data = data;

      response = '0;
      response.status = expected_status;

      async_request(request, response);
    endtask;

    // Queue a simple read transaction with automated response checking
    task async_read(
      logic [CTRLPORT_ADDR_W-1:0] addr,
      logic [CTRLPORT_DATA_W-1:0] expected_data,
      ctrlport_status_t expected_status = STS_OKAY
    );
      ctrlport_request_t request;
      ctrlport_response_t response;

      request = '0;
      request.rd = '1;
      request.addr = addr;

      response = '0;
      response.status = expected_status;
      response.data = expected_data;

      async_request(request, response);
    endtask;

    // wait for all transactions to be processed
    task wait_complete();
      while(transactions.num() > 0) begin
        @(posedge iface.clk);
      end
    endtask

    // ------------------------------------------------------------------
    // Synchronous transaction handling
    // ------------------------------------------------------------------
    // Perform a request and get response
    task request(
      input ctrlport_request_t request,
      input ctrlport_response_t expected_response,
      output logic[CTRLPORT_DATA_W-1:0] data
    );
      async_request(request, expected_response);
      wait_complete();
      data = reponse_data;
    endtask;

    // Perform a simple write transaction
    task write(
      logic[CTRLPORT_ADDR_W-1:0] addr,
      logic[CTRLPORT_DATA_W-1:0] data,
      ctrlport_status_t expected_status = STS_OKAY
    );
      async_write(addr, data, expected_status);
      wait_complete();
    endtask;

    // Perform a simple read transaction, no response data check, return data from interface
    task read(
      input logic[CTRLPORT_ADDR_W-1:0] addr,
      output logic[CTRLPORT_DATA_W-1:0] data,
      input ctrlport_status_t expected_status = STS_OKAY
    );
      ctrlport_request_t request;
      ctrlport_response_t response;

      request = '0;
      request.rd = '1;
      request.addr = addr;

      response = '0;
      response.status = expected_status;

      async_request(request, response, '1);
      wait_complete();
      data = reponse_data;
    endtask;


    // ------------------------------------------------------------------
    // Signal handling
    // ------------------------------------------------------------------
    // Start the BFM.
    // This will join a separate thread for the interface handling.
    task run();
      fork
        request_body();
      join_none
    endtask

    // Control the master request interface
    local task request_body();
      ctrlport_transfer_t transfer;
      ctrlport_request_t request_idle;

      // initialize request interface
      request_idle = 'x;
      request_idle.wr = '0;
      request_idle.rd = '0;
      iface.req <= request_idle;

      // ignore first clock cycle to let response settle
      @(posedge iface.clk);

      forever begin
        // handle any available transaction (but leave it in the mailbox for now)
        if (transactions.try_peek(transfer)) begin
          // wait for reset to be deasserted
          while(iface.rst) begin
            @(posedge iface.clk);
            check_no_response();
          end

          // send request
          iface.req <= transfer.req;
          // check minimum time for response on interface
          @(negedge iface.clk);
          check_no_response();

          // reset request interface
          @(posedge iface.clk);
          iface.req <= request_idle;

          // wait for response
          while(!iface.resp.ack) begin
            @(posedge iface.clk);
          end

          // status is always expected to match
          assert (iface.resp.status == transfer.resp.status) else begin
            $error("Unexpected status received on interface. Expected: 0b%2b Received: 0b%2b",
              transfer.resp.status, iface.resp.status);
          end

          // check data if read and data check is not skipped
          if (transfer.req.rd && !transfer.skip_data_check) begin
            assert (iface.resp.data == transfer.resp.data) else begin
              $error("Unexpected data received on interface. Expected: 0x%h Received: 0x%h",
                transfer.resp.data, iface.resp.data);
            end
          end

          // save data for read operations
          reponse_data = iface.resp.data;

          // request is done -> remove from queue
          transactions.get(transfer);

        // wait at least one clock cycle for next check of mailbox
        end else begin
          @(posedge iface.clk);
          check_no_response();
        end
      end
    endtask

    // Check for no response in this clock cycle
    local task check_no_response();
      if (iface.resp.ack != '0) begin
        $error("Unexpected response received on interface: %p", iface.resp);
      end
    endtask

  endclass

endpackage