base: remove Trace::enabled flag
[gem5.git] / util / tlm / sc_target.cc
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
37 using namespace sc_core;
38 using namespace std;
39
40 Target::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
68 void
69 Target::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
70 {
71 /* Execute the read or write commands */
72 execute_transaction(trans);
73 }
74
75 unsigned int
76 Target::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 */
103 tlm::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
112 void
113 Target::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
160 void
161 Target::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, 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, SC_NS); // Latency
177 target_done_event.notify(delay);
178
179 assert(transaction_in_progress == 0);
180 transaction_in_progress = &trans;
181 }
182
183 void
184 Target::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
203 void
204 Target::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
243 void
244 Target::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, 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 }