sc_target.cc revision 11818:f12963cb9dc2
1/*
2 * Copyright (c) 2015, University of Kaiserslautern
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 *    this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 *    contributors may be used to endorse or promote products derived from
18 *    this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
24 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Authors: Matthias Jung
33 */
34
35#include "sc_target.hh"
36
37using namespace sc_core;
38using namespace std;
39
40Target::Target(sc_core::sc_module_name name,
41    bool debug,
42    unsigned long long int size,
43    unsigned int offset) :
44    socket("socket"),
45    transaction_in_progress(0),
46    response_in_progress(false),
47    next_response_pending(0),
48    end_req_pending(0),
49    m_peq(this, &Target::peq_cb),
50    debug(debug),
51    size(size),
52    offset(offset)
53{
54    /* Register tlm transport functions */
55    socket.register_b_transport(this, &Target::b_transport);
56    socket.register_transport_dbg(this, &Target::transport_dbg);
57    socket.register_nb_transport_fw(this, &Target::nb_transport_fw);
58
59
60    /* allocate storage memory */
61    mem = new unsigned char[size];
62
63    SC_METHOD(execute_transaction_process);
64    sensitive << target_done_event;
65    dont_initialize();
66}
67
68void
69Target::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
70{
71    /* Execute the read or write commands */
72    execute_transaction(trans);
73}
74
75unsigned int
76Target::transport_dbg(tlm::tlm_generic_payload& trans)
77{
78    tlm::tlm_command cmd = trans.get_command();
79    sc_dt::uint64    adr = trans.get_address() - offset;
80    unsigned char*   ptr = trans.get_data_ptr();
81    unsigned int     len = trans.get_data_length();
82
83    unsigned char *mem_array_ptr = mem + adr;
84
85    /* Load / Store the access: */
86    if ( cmd == tlm::TLM_READ_COMMAND ) {
87        if (debug) {
88            SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND");
89        }
90        std::memcpy(ptr, mem_array_ptr, len);
91    } else if ( cmd == tlm::TLM_WRITE_COMMAND ) {
92        if (debug) {
93            SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND");
94        }
95        std::memcpy(mem_array_ptr, ptr, len);
96    }
97
98    return len;
99}
100
101
102/* TLM-2 non-blocking transport method */
103tlm::tlm_sync_enum Target::nb_transport_fw(tlm::tlm_generic_payload& trans,
104                                           tlm::tlm_phase& phase,
105                                           sc_time& delay)
106{
107    /* Queue the transaction until the annotated time has elapsed */
108    m_peq.notify(trans, phase, delay);
109    return tlm::TLM_ACCEPTED;
110}
111
112void
113Target::peq_cb(tlm::tlm_generic_payload& trans,
114               const tlm::tlm_phase& phase)
115{
116    sc_time delay;
117
118    if (phase == tlm::BEGIN_REQ) {
119        if (debug) SC_REPORT_INFO("target", "tlm::BEGIN_REQ");
120
121        /* Increment the transaction reference count */
122        trans.acquire();
123
124        if ( !transaction_in_progress ) {
125            send_end_req(trans);
126        } else {
127            /* Put back-pressure on initiator by deferring END_REQ until
128             * pipeline is clear */
129            end_req_pending = &trans;
130        }
131    } else if (phase == tlm::END_RESP) {
132        /* On receiving END_RESP, the target can release the transaction and
133         * allow other pending transactions to proceed */
134        if (!response_in_progress) {
135            SC_REPORT_FATAL("TLM-2", "Illegal transaction phase END_RESP"
136                            "received by target");
137        }
138
139        transaction_in_progress = 0;
140
141        /* Target itself is now clear to issue the next BEGIN_RESP */
142        response_in_progress = false;
143        if (next_response_pending) {
144            send_response( *next_response_pending );
145            next_response_pending = 0;
146        }
147
148        /* ... and to unblock the initiator by issuing END_REQ */
149        if (end_req_pending) {
150            send_end_req( *end_req_pending );
151            end_req_pending = 0;
152        }
153
154    } else /* tlm::END_REQ or tlm::BEGIN_RESP */ {
155            SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by"
156                            "target");
157    }
158}
159
160void
161Target::send_end_req(tlm::tlm_generic_payload& trans)
162{
163    tlm::tlm_phase bw_phase;
164    sc_time delay;
165
166    /* Queue the acceptance and the response with the appropriate latency */
167    bw_phase = tlm::END_REQ;
168    delay = sc_time(10.0, SC_NS); // Accept delay
169
170    tlm::tlm_sync_enum status;
171    status = socket->nb_transport_bw(trans, bw_phase, delay);
172
173    /* Ignore return value;
174     * initiator cannot terminate transaction at this point
175     * Queue internal event to mark beginning of response: */
176    delay = delay + sc_time(40.0, SC_NS); // Latency
177    target_done_event.notify(delay);
178
179    assert(transaction_in_progress == 0);
180    transaction_in_progress = &trans;
181}
182
183void
184Target::execute_transaction_process()
185{
186    /* Execute the read or write commands */
187    execute_transaction( *transaction_in_progress );
188
189    /* Target must honor BEGIN_RESP/END_RESP exclusion rule; i.e. must not
190     * send BEGIN_RESP until receiving previous END_RESP or BEGIN_REQ */
191    if (response_in_progress) {
192        /* Target allows only two transactions in-flight */
193        if (next_response_pending) {
194            SC_REPORT_FATAL("TLM-2", "Attempt to have two pending responses"
195                            "in target");
196        }
197        next_response_pending = transaction_in_progress;
198    } else {
199        send_response( *transaction_in_progress );
200    }
201}
202
203void
204Target::execute_transaction(tlm::tlm_generic_payload& trans)
205{
206    tlm::tlm_command cmd = trans.get_command();
207    sc_dt::uint64    adr = trans.get_address() - offset;
208    unsigned char*   ptr = trans.get_data_ptr();
209    unsigned int     len = trans.get_data_length();
210    unsigned char*   byt = trans.get_byte_enable_ptr();
211    unsigned int     wid = trans.get_streaming_width();
212
213    if ( byt != 0 ) {
214        cout << "Byte Error" << endl;
215        trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE );
216        return;
217    }
218
219    //if ( len > 4 || wid < len ) {
220    //    cout << "Burst Error len=" << len << " wid=" << wid << endl;
221    //    trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE );
222    //    return;
223    //}
224
225    unsigned char *mem_array_ptr = mem + adr;
226
227    /* Load / Store the access: */
228    if ( cmd == tlm::TLM_READ_COMMAND ) {
229        if (debug) {
230            SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND");
231        }
232        std::memcpy(ptr, mem_array_ptr, len);
233    } else if ( cmd == tlm::TLM_WRITE_COMMAND ) {
234        if (debug) {
235            SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND");
236        }
237        std::memcpy(mem_array_ptr, ptr, len);
238    }
239
240    trans.set_response_status( tlm::TLM_OK_RESPONSE );
241}
242
243void
244Target::send_response(tlm::tlm_generic_payload& trans)
245{
246    tlm::tlm_sync_enum status;
247    tlm::tlm_phase bw_phase;
248    sc_time delay;
249
250    response_in_progress = true;
251    bw_phase = tlm::BEGIN_RESP;
252    delay = sc_time(10.0, SC_NS);
253    status = socket->nb_transport_bw( trans, bw_phase, delay );
254
255    if (status == tlm::TLM_UPDATED) {
256        /* The timing annotation must be honored */
257        m_peq.notify(trans, bw_phase, delay);
258    } else if (status == tlm::TLM_COMPLETED) {
259        /* The initiator has terminated the transaction */
260        transaction_in_progress = 0;
261        response_in_progress = false;
262    }
263    trans.release();
264}
265