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