sc_target.cc (11818:f12963cb9dc2) sc_target.cc (12048:a280e9bc358d)
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
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::check_address(unsigned long long int addr)
70{
71 if (addr < offset || addr >= offset + size)
72 SC_REPORT_FATAL("Target", "Address out of range. Did you set an "
73 "appropriate size and offset?");
74}
75
76void
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{
77Target::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
78{
79 /* Execute the read or write commands */
80 execute_transaction(trans);
81}
82
83unsigned int
84Target::transport_dbg(tlm::tlm_generic_payload& trans)
85{
86 check_address(trans.get_address());
87
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{
88 tlm::tlm_command cmd = trans.get_command();
89 sc_dt::uint64 adr = trans.get_address() - offset;
90 unsigned char* ptr = trans.get_data_ptr();
91 unsigned int len = trans.get_data_length();
92
93 unsigned char *mem_array_ptr = mem + adr;
94
95 /* Load / Store the access: */
96 if ( cmd == tlm::TLM_READ_COMMAND ) {
97 if (debug) {
98 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND");
99 }
100 std::memcpy(ptr, mem_array_ptr, len);
101 } else if ( cmd == tlm::TLM_WRITE_COMMAND ) {
102 if (debug) {
103 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND");
104 }
105 std::memcpy(mem_array_ptr, ptr, len);
106 }
107
108 return len;
109}
110
111
112/* TLM-2 non-blocking transport method */
113tlm::tlm_sync_enum Target::nb_transport_fw(tlm::tlm_generic_payload& trans,
114 tlm::tlm_phase& phase,
115 sc_time& delay)
116{
117 /* Queue the transaction until the annotated time has elapsed */
118 m_peq.notify(trans, phase, delay);
119 return tlm::TLM_ACCEPTED;
120}
121
122void
123Target::peq_cb(tlm::tlm_generic_payload& trans,
124 const tlm::tlm_phase& phase)
125{
126 sc_time delay;
127
128 if (phase == tlm::BEGIN_REQ) {
129 if (debug) SC_REPORT_INFO("target", "tlm::BEGIN_REQ");
130
131 /* Increment the transaction reference count */
132 trans.acquire();
133
134 if ( !transaction_in_progress ) {
135 send_end_req(trans);
136 } else {
137 /* Put back-pressure on initiator by deferring END_REQ until
138 * pipeline is clear */
139 end_req_pending = &trans;
140 }
141 } else if (phase == tlm::END_RESP) {
142 /* On receiving END_RESP, the target can release the transaction and
143 * allow other pending transactions to proceed */
144 if (!response_in_progress) {
145 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase END_RESP"
146 "received by target");
147 }
148
149 transaction_in_progress = 0;
150
151 /* Target itself is now clear to issue the next BEGIN_RESP */
152 response_in_progress = false;
153 if (next_response_pending) {
154 send_response( *next_response_pending );
155 next_response_pending = 0;
156 }
157
158 /* ... and to unblock the initiator by issuing END_REQ */
159 if (end_req_pending) {
160 send_end_req( *end_req_pending );
161 end_req_pending = 0;
162 }
163
164 } else /* tlm::END_REQ or tlm::BEGIN_RESP */ {
165 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by"
166 "target");
167 }
168}
169
170void
171Target::send_end_req(tlm::tlm_generic_payload& trans)
172{
173 tlm::tlm_phase bw_phase;
174 sc_time delay;
175
176 /* Queue the acceptance and the response with the appropriate latency */
177 bw_phase = tlm::END_REQ;
178 delay = sc_time(10.0, SC_NS); // Accept delay
179
180 tlm::tlm_sync_enum status;
181 status = socket->nb_transport_bw(trans, bw_phase, delay);
182
183 /* Ignore return value;
184 * initiator cannot terminate transaction at this point
185 * Queue internal event to mark beginning of response: */
186 delay = delay + sc_time(40.0, SC_NS); // Latency
187 target_done_event.notify(delay);
188
189 assert(transaction_in_progress == 0);
190 transaction_in_progress = &trans;
191}
192
193void
194Target::execute_transaction_process()
195{
196 /* Execute the read or write commands */
197 execute_transaction( *transaction_in_progress );
198
199 /* Target must honor BEGIN_RESP/END_RESP exclusion rule; i.e. must not
200 * send BEGIN_RESP until receiving previous END_RESP or BEGIN_REQ */
201 if (response_in_progress) {
202 /* Target allows only two transactions in-flight */
203 if (next_response_pending) {
204 SC_REPORT_FATAL("TLM-2", "Attempt to have two pending responses"
205 "in target");
206 }
207 next_response_pending = transaction_in_progress;
208 } else {
209 send_response( *transaction_in_progress );
210 }
211}
212
213void
214Target::execute_transaction(tlm::tlm_generic_payload& trans)
215{
216 check_address(trans.get_address());
217
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}
218 tlm::tlm_command cmd = trans.get_command();
219 sc_dt::uint64 adr = trans.get_address() - offset;
220 unsigned char* ptr = trans.get_data_ptr();
221 unsigned int len = trans.get_data_length();
222 unsigned char* byt = trans.get_byte_enable_ptr();
223 unsigned int wid = trans.get_streaming_width();
224
225 if ( byt != 0 ) {
226 cout << "Byte Error" << endl;
227 trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE );
228 return;
229 }
230
231 //if ( len > 4 || wid < len ) {
232 // cout << "Burst Error len=" << len << " wid=" << wid << endl;
233 // trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE );
234 // return;
235 //}
236
237 unsigned char *mem_array_ptr = mem + adr;
238
239 /* Load / Store the access: */
240 if ( cmd == tlm::TLM_READ_COMMAND ) {
241 if (debug) {
242 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND");
243 }
244 std::memcpy(ptr, mem_array_ptr, len);
245 } else if ( cmd == tlm::TLM_WRITE_COMMAND ) {
246 if (debug) {
247 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND");
248 }
249 std::memcpy(mem_array_ptr, ptr, len);
250 }
251
252 trans.set_response_status( tlm::TLM_OK_RESPONSE );
253}
254
255void
256Target::send_response(tlm::tlm_generic_payload& trans)
257{
258 tlm::tlm_sync_enum status;
259 tlm::tlm_phase bw_phase;
260 sc_time delay;
261
262 response_in_progress = true;
263 bw_phase = tlm::BEGIN_RESP;
264 delay = sc_time(10.0, SC_NS);
265 status = socket->nb_transport_bw( trans, bw_phase, delay );
266
267 if (status == tlm::TLM_UPDATED) {
268 /* The timing annotation must be honored */
269 m_peq.notify(trans, bw_phase, delay);
270 } else if (status == tlm::TLM_COMPLETED) {
271 /* The initiator has terminated the transaction */
272 transaction_in_progress = 0;
273 response_in_progress = false;
274 }
275 trans.release();
276}