1 /*****************************************************************************
2
3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4 more contributor license agreements. See the NOTICE file distributed
5 with this work for additional information regarding copyright ownership.
6 Accellera licenses this file to you under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with the
8 License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 permissions and limitations under the License.
17
18 *****************************************************************************/
19
20 //=====================================================================
21 /// @file me_traffic_generator.cpp
22 //
23 /// @brief traffic generation routines
24 //
25 //=====================================================================
26 // Authors:
27 // Bill Bunton, ESLX
28 // Jack Donovan, ESLX
29 // Charles Wilson, ESLX
30 //====================================================================
31
32
33
34 #include "reporting.h" // reporting macros
35 #include "me_traffic_generator.h" // traffic generator declarations
36
37 #ifdef _MSC_VER
38 #if (_MSC_VER < 1300)
39 typedef unsigned char uint8_t;
40 typedef unsigned short uint16_t;
41 typedef unsigned int uint32_t;
42 #else
43 typedef unsigned __int8 uint8_t;
44 typedef unsigned __int16 uint16_t;
45 typedef unsigned __int32 uint32_t;
46 #endif
47 #elif defined( __sparc ) || defined( __sparc__ )
48 typedef unsigned char uint8_t;
49 typedef unsigned short uint16_t;
50 typedef unsigned int uint32_t;
51 #else
52 #include <stdint.h>
53 #endif
54
55 using namespace std;
56
57 static const char *filename = "me_traffic_generator.cpp"; ///< filename for reporting
58
59 /// Constructor
60
61 SC_HAS_PROCESS(me_traffic_generator);
62 //-----------------------------------------------------------------------------
63 //
me_traffic_generator(sc_core::sc_module_name name,const unsigned int ID,sc_dt::uint64 base_address_1,sc_dt::uint64 base_address_2)64 me_traffic_generator::me_traffic_generator // constructor
65 ( sc_core::sc_module_name name // instance name
66 , const unsigned int ID // initiator ID
67 , sc_dt::uint64 base_address_1 // first base address
68 , sc_dt::uint64 base_address_2 // second base address
69 )
70 : sc_module ( name ) /// module name
71 , m_ID ( ID ) /// initiator ID
72 , m_base_address_1 ( base_address_1 ) /// first base address
73 , m_base_address_2 ( base_address_2 ) /// second base address
74 {
75 SC_THREAD(me_traffic_generator_thread);
76 me_ui_waiters.push_back(this);
77 // odd IDs are big endian, even are little
78 m_endianness = ((m_ID & 1) == 0 ? tlm::TLM_LITTLE_ENDIAN : tlm::TLM_BIG_ENDIAN);
79 // host endianness
80 m_host_endianness = tlm::get_host_endianness();
81 std::ostringstream tmp;
82 tmp << m_ID << (m_endianness == tlm::TLM_LITTLE_ENDIAN ? " LE" : " BE") << "32 ";
83 m_prompt = tmp.str();
84 }
85
86
87 /// SystemC thread for generation of GP traffic
88
89 //-----------------------------------------------------------------------------
90 //
91 void
me_traffic_generator_thread(void)92 me_traffic_generator::me_traffic_generator_thread
93 ( void
94 )
95 {
96 std::ostringstream msg; ///< log message
97 msg.str ("");
98 msg << "Initiator: " << m_ID << " Starting Traffic";
99 REPORT_INFO(filename, __FUNCTION__, msg.str());
100
101 bool running = true;
102 while(running) {
103 // traffic generator should own the user interface
104 while(me_ui_waiters.front() != this) wait(me_ui_change_event);
105
106 // get user input
107 std::cout << m_prompt << " > ";
108 std::string user_command;
109 std::getline(std::cin, user_command);
110 std::cout << std::endl;
111 if(std::cin.bad() || std::cin.fail() || std::cin.bad()) user_command = string("q");
112
113 // parse for control flow
114 if(user_command.length() != 0) switch(user_command[0]) {
115 case 'l': // load
116 case 's': // store
117 do_transaction(user_command);
118 break;
119
120 case 'w': // wait
121 me_ui_waiters.pop_front();
122 me_ui_waiters.push_back(this);
123 me_ui_change_event.notify();
124 break;
125
126 case 'q': // quit
127 me_ui_waiters.pop_front();
128 me_ui_change_event.notify();
129 running = false;
130 break;
131
132 case 'm':
133 std::cout << "Memory map:\n";
134 std::cout << " " << hex << m_base_address_1 << " (16)" << dec << endl;
135 std::cout << " " << hex << m_base_address_2 << " (16)" << dec << endl;
136 break;
137
138 case 'h': // help
139 case 'H': // help
140 case '?': // help
141 std::cout << "enter one of the following commands (all numbers in hex):\n";
142 std::cout << " l8 addr nr_bytes (load)\n";
143 std::cout << " l16 addr nr_halfwords (load)\n";
144 std::cout << " l32 addr nr_words (load)\n";
145 std::cout << " s8 addr d0 d1 ... (store)\n";
146 std::cout << " s16 addr d0 d1 ... (store)\n";
147 std::cout << " s32 addr d0 d1 ... (store)\n";
148 std::cout << " m (memory map)\n";
149 std::cout << " w (wait/switch initiator)\n";
150 std::cout << " q (quit)\n";
151 break;
152 }
153 }
154
155 msg.str ("");
156 msg << "Traffic Generator : " << m_ID << endl
157 << "=========================================================" << endl
158 << " #### Traffic Generator Complete #### ";
159 REPORT_INFO(filename, __FUNCTION__, msg.str());
160
161 } // end me_traffic_generator_thread
162
163
164 /// Synchronisation between mixed-endian traffic generators
165 std::list<me_traffic_generator *> me_traffic_generator::me_ui_waiters;
166 sc_core::sc_event me_traffic_generator::me_ui_change_event;
167
168
169 /// Helper functions
do_transaction(std::string & user_command)170 void me_traffic_generator::do_transaction(std::string &user_command) {
171 std::cout << m_prompt << ":: cmd: " << user_command << std::endl;
172 std::istringstream iss(user_command);
173
174 char ldst;
175 iss >> ldst;
176
177 if(ldst == 'l') do_load(iss);
178 else do_store(iss);
179 }
180
do_load(std::istringstream & iss)181 void me_traffic_generator::do_load(std::istringstream &iss) {
182 int datatype;
183 iss >> datatype;
184
185 switch(datatype) {
186 case 8:
187 do_do_load<uint8_t>(iss);
188 break;
189 case 16:
190 do_do_load<uint16_t>(iss);
191 break;
192 case 32:
193 default:
194 do_do_load<uint32_t>(iss);
195 break;
196 }
197 }
198
do_store(std::istringstream & iss)199 void me_traffic_generator::do_store(std::istringstream &iss) {
200 int datatype;
201 iss >> datatype;
202
203 switch(datatype) {
204 case 8:
205 do_do_store<uint8_t>(iss);
206 break;
207 case 16:
208 do_do_store<uint16_t>(iss);
209 break;
210 case 32:
211 default:
212 do_do_store<uint32_t>(iss);
213 break;
214 }
215 }
216
do_do_load(std::istringstream & iss)217 template<typename T> void me_traffic_generator::do_do_load(std::istringstream &iss) {
218 tlm::tlm_generic_payload *req_transaction_ptr = m_txn_pool.pop();
219
220 sc_dt::uint64 addr;
221 iss >> hex >> addr >> dec;
222 int len;
223 iss >> hex >> len >> dec;
224 if(int(len * sizeof(T)) > m_buffer_size) return;
225
226 req_transaction_ptr->set_command(tlm::TLM_READ_COMMAND);
227 req_transaction_ptr->set_address(addr);
228 req_transaction_ptr->set_data_ptr(m_buffer);
229 req_transaction_ptr->set_data_length(len * sizeof(T));
230 req_transaction_ptr->set_streaming_width(len * sizeof(T));
231 req_transaction_ptr->set_byte_enable_ptr(0);
232 req_transaction_ptr->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
233
234 if(m_endianness != m_host_endianness)
235 tlm::tlm_to_hostendian_word<T>(req_transaction_ptr,4);
236
237 request_out_port->write(req_transaction_ptr);
238 tlm::tlm_generic_payload *resp_transaction_ptr = response_in_port->read();
239
240 if (resp_transaction_ptr != req_transaction_ptr) {
241 std::ostringstream msg;
242 msg << m_ID << "Response to wrong request";
243 REPORT_FATAL(filename, __FUNCTION__, msg.str());
244 }
245 if (resp_transaction_ptr->get_response_status() != tlm::TLM_OK_RESPONSE) {
246 std::ostringstream msg;
247 msg << m_ID << "Transaction ERROR";
248 REPORT_FATAL(filename, __FUNCTION__, msg.str());
249 }
250
251 if(m_endianness != m_host_endianness)
252 tlm::tlm_from_hostendian_word<T>(req_transaction_ptr,4);
253
254 std::cout << m_prompt << ":: " << "read transaction length " << len
255 << " (10) x " << sizeof(T)*8 << "-bit completed, returning:" << std::endl;
256
257 T *buffer = (T *)m_buffer;
258 std::cout << m_prompt << "::";
259 for(int i=0; i<len; i++) {
260 std::cout << " " << hex << unsigned(*(buffer++));
261 }
262 std::cout << dec << std::endl;
263
264 m_txn_pool.push(resp_transaction_ptr);
265 }
266
do_do_store(std::istringstream & iss)267 template<typename T> void me_traffic_generator::do_do_store(std::istringstream &iss) {
268 tlm::tlm_generic_payload *req_transaction_ptr = m_txn_pool.pop();
269
270 sc_dt::uint64 addr;
271 iss >> hex >> addr >> dec;
272
273 T *buffer = (T *)m_buffer;
274 int len;
275 for(len=0; len < m_buffer_size; len++) {
276 unsigned tmp;
277 iss >> hex >> tmp >> dec;
278 if(iss.fail()) break;
279 *(buffer++) = T(tmp);
280 }
281 if(len == 0) return;
282
283 req_transaction_ptr->set_command(tlm::TLM_WRITE_COMMAND);
284 req_transaction_ptr->set_address(addr);
285 req_transaction_ptr->set_data_ptr(m_buffer);
286 req_transaction_ptr->set_data_length(len * sizeof(T));
287 req_transaction_ptr->set_streaming_width(len * sizeof(T));
288 req_transaction_ptr->set_byte_enable_ptr(0);
289 req_transaction_ptr->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
290
291 if(m_endianness != m_host_endianness)
292 tlm::tlm_to_hostendian_word<T>(req_transaction_ptr,4);
293
294 request_out_port->write(req_transaction_ptr);
295 tlm::tlm_generic_payload *resp_transaction_ptr = response_in_port->read();
296
297 if (resp_transaction_ptr != req_transaction_ptr) {
298 std::ostringstream msg;
299 msg << m_ID << "Response to wrong request";
300 REPORT_FATAL(filename, __FUNCTION__, msg.str());
301 }
302 if (resp_transaction_ptr->get_response_status() != tlm::TLM_OK_RESPONSE) {
303 std::ostringstream msg;
304 msg << m_ID << "Transaction ERROR";
305 REPORT_FATAL(filename, __FUNCTION__, msg.str());
306 }
307
308 if(m_endianness != m_host_endianness)
309 tlm::tlm_from_hostendian_word<T>(req_transaction_ptr,4);
310
311 std::cout << m_prompt << ":: " << "write transaction length " << len
312 << " (10) x " << sizeof(T)*8 << "-bit completed" << std::endl;
313
314 m_txn_pool.push(resp_transaction_ptr);
315 }
316
317