2 * Copyright (c) 2015, University of Kaiserslautern
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
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.
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.
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.
32 * Authors: Matthias Jung
35 #include "sc_target.hh"
37 using namespace sc_core
;
40 Target::Target(sc_core::sc_module_name name
,
42 unsigned long long int size
,
43 unsigned int offset
) :
45 transaction_in_progress(0),
46 response_in_progress(false),
47 next_response_pending(0),
49 m_peq(this, &Target::peq_cb
),
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
);
60 /* allocate storage memory */
61 mem
= new unsigned char[size
];
63 SC_METHOD(execute_transaction_process
);
64 sensitive
<< target_done_event
;
69 Target::b_transport(tlm::tlm_generic_payload
& trans
, sc_time
& delay
)
71 /* Execute the read or write commands */
72 execute_transaction(trans
);
76 Target::transport_dbg(tlm::tlm_generic_payload
& trans
)
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();
83 unsigned char *mem_array_ptr
= mem
+ adr
;
85 /* Load / Store the access: */
86 if ( cmd
== tlm::TLM_READ_COMMAND
) {
88 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND");
90 std::memcpy(ptr
, mem_array_ptr
, len
);
91 } else if ( cmd
== tlm::TLM_WRITE_COMMAND
) {
93 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND");
95 std::memcpy(mem_array_ptr
, ptr
, len
);
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
,
107 /* Queue the transaction until the annotated time has elapsed */
108 m_peq
.notify(trans
, phase
, delay
);
109 return tlm::TLM_ACCEPTED
;
113 Target::peq_cb(tlm::tlm_generic_payload
& trans
,
114 const tlm::tlm_phase
& phase
)
118 if(phase
== tlm::BEGIN_REQ
) {
119 if(debug
) SC_REPORT_INFO("target", "tlm::BEGIN_REQ");
121 /* Increment the transaction reference count */
124 if ( !transaction_in_progress
) {
127 /* Put back-pressure on initiator by deferring END_REQ until
128 * pipeline is clear */
129 end_req_pending
= &trans
;
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");
139 transaction_in_progress
= 0;
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;
148 /* ... and to unblock the initiator by issuing END_REQ */
149 if (end_req_pending
) {
150 send_end_req( *end_req_pending
);
154 } else /* tlm::END_REQ or tlm::BEGIN_RESP */ {
155 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by"
161 Target::send_end_req(tlm::tlm_generic_payload
& trans
)
163 tlm::tlm_phase bw_phase
;
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
170 tlm::tlm_sync_enum status
;
171 status
= socket
->nb_transport_bw(trans
, bw_phase
, delay
);
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
);
179 assert(transaction_in_progress
== 0);
180 transaction_in_progress
= &trans
;
184 Target::execute_transaction_process()
186 /* Execute the read or write commands */
187 execute_transaction( *transaction_in_progress
);
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"
197 next_response_pending
= transaction_in_progress
;
199 send_response( *transaction_in_progress
);
204 Target::execute_transaction(tlm::tlm_generic_payload
& trans
)
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();
214 cout
<< "Byte Error" << endl
;
215 trans
.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE
);
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 );
225 unsigned char *mem_array_ptr
= mem
+ adr
;
227 /* Load / Store the access: */
228 if ( cmd
== tlm::TLM_READ_COMMAND
) {
230 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND");
232 std::memcpy(ptr
, mem_array_ptr
, len
);
233 } else if ( cmd
== tlm::TLM_WRITE_COMMAND
) {
235 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND");
237 std::memcpy(mem_array_ptr
, ptr
, len
);
240 trans
.set_response_status( tlm::TLM_OK_RESPONSE
);
244 Target::send_response(tlm::tlm_generic_payload
& trans
)
246 tlm::tlm_sync_enum status
;
247 tlm::tlm_phase bw_phase
;
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
);
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;