SimpleLTInitiator2_DMI.h revision 12922
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// Nov 06, 2008 22// 23// Updated by: 24// Xiaopeng Qiu, JEDA Technologies, Inc 25// Email: qiuxp@jedatechnologies.net 26// 27// To fix violations of TLM2.0 rules, which are detected by JEDA 28// TLM2.0 checker. 29// 30//==================================================================== 31 32#ifndef __SIMPLE_LT_INITIATOR2_DMI_H__ 33#define __SIMPLE_LT_INITIATOR2_DMI_H__ 34 35#include "tlm.h" 36#include "tlm_utils/simple_initiator_socket.h" 37#include <systemc> 38#include <cassert> 39#include <iostream> 40#include <iomanip> 41#include <map> 42 43class SimpleLTInitiator2_dmi : public sc_core::sc_module 44{ 45public: 46 typedef tlm::tlm_generic_payload transaction_type; 47 typedef tlm::tlm_dmi dmi_type; 48 typedef tlm::tlm_phase phase_type; 49 typedef tlm::tlm_sync_enum sync_enum_type; 50 typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator2_dmi> initiator_socket_type; 51 52public: 53 initiator_socket_type socket; 54 55public: 56 SC_HAS_PROCESS(SimpleLTInitiator2_dmi); 57 SimpleLTInitiator2_dmi(sc_core::sc_module_name name, 58 unsigned int nrOfTransactions = 0x5, 59 unsigned int baseAddress = 0x0) : 60 sc_core::sc_module(name), 61 socket("socket"), 62 mNrOfTransactions(nrOfTransactions), 63 mBaseAddress(baseAddress), 64 mTransactionCount(0) 65 { 66 mDMIDataReads.first.set_start_address(1); 67 mDMIDataReads.first.set_end_address(0); 68 mDMIDataWrites.first.set_start_address(1); 69 mDMIDataWrites.first.set_end_address(0); 70 71 // register invalidate method 72 socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator2_dmi::invalidate_direct_mem_ptr); 73 74 // Initiator thread 75 SC_THREAD(run); 76 } 77 78 bool initTransaction(transaction_type& trans) 79 { 80 if (mTransactionCount < mNrOfTransactions) { 81 trans.set_address(mBaseAddress + 4*mTransactionCount); 82 mData = mTransactionCount; 83 trans.set_command(tlm::TLM_WRITE_COMMAND); 84 85 } else if (mTransactionCount < 2 * mNrOfTransactions) { 86 trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions)); 87 mData = 0; 88 trans.set_command(tlm::TLM_READ_COMMAND); 89 90 } else { 91 return false; 92 } 93 94 trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData)); 95 trans.set_data_length(4); 96 trans.set_streaming_width(4); 97 trans.set_dmi_allowed(false); 98 trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); 99 100 ++mTransactionCount; 101 return true; 102 } 103 104 void logStartTransation(transaction_type& trans) 105 { 106 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 107 std::cout << name() << ": Send write request: A = 0x" 108 << std::hex << (unsigned int)trans.get_address() 109 << ", D = 0x" << mData << std::dec 110 << " @ " << sc_core::sc_time_stamp() << std::endl; 111 112 } else { 113 std::cout << name() << ": Send read request: A = 0x" 114 << std::hex << (unsigned int)trans.get_address() << std::dec 115 << " @ " << sc_core::sc_time_stamp() << std::endl; 116 } 117 } 118 119 void logEndTransaction(transaction_type& trans) 120 { 121 if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) { 122 std::cout << name() << ": Received error response @ " 123 << sc_core::sc_time_stamp() << std::endl; 124 125 } else { 126 std::cout << name() << ": Received ok response"; 127 if (trans.get_command() == tlm::TLM_READ_COMMAND) { 128 std::cout << ": D = 0x" << std::hex << mData << std::dec; 129 } 130 std::cout << " @ " << sc_core::sc_time_stamp() << std::endl; 131 } 132 } 133 134 std::pair<dmi_type, bool>& getDMIData(const transaction_type& trans) 135 { 136 if (trans.get_command() == tlm::TLM_READ_COMMAND) { 137 return mDMIDataReads; 138 139 } else { // WRITE 140 return mDMIDataWrites; 141 } 142 } 143 144 void run() 145 { 146 transaction_type trans; 147 sc_core::sc_time t; 148 149 while (initTransaction(trans)) { 150 // Create transaction and initialise t 151 t = sc_core::SC_ZERO_TIME; 152 153 logStartTransation(trans); 154 155 /////////////////////////////////////////////////////////// 156 // DMI handling: 157 // We do *not* use the DMI hint to check if it makes sense to ask for 158 // DMI pointers. So the pattern is: 159 // - if the address is not covered by a DMI region try to acquire DMI 160 // pointers 161 // - if we have a DMI pointer, do the DMI "transaction" 162 // - otherwise fall back to a normal transaction 163 /////////////////////////////////////////////////////////// 164 165 std::pair<dmi_type, bool>& dmi_data = getDMIData(trans); 166 167 // Check if we need to acquire a DMI pointer 168 if((trans.get_address() < dmi_data.first.get_start_address()) || 169 (trans.get_address() > dmi_data.first.get_end_address()) ) 170 { 171 sc_dt::uint64 address = trans.get_address(); //save original address 172 dmi_data.second = 173 socket->get_direct_mem_ptr(trans, 174 dmi_data.first); 175 trans.set_address(address); 176 } 177 // Do DMI "transaction" if we have a valid region 178 if (dmi_data.second && 179 (trans.get_address() >= dmi_data.first.get_start_address()) && 180 (trans.get_address() <= dmi_data.first.get_end_address()) ) 181 { 182 // We can handle the data here. As the logEndTransaction is assuming 183 // something to happen in the data structure, we really need to 184 // do this: 185 trans.set_response_status(tlm::TLM_OK_RESPONSE); 186 sc_dt::uint64 tmp = trans.get_address() - dmi_data.first.get_start_address(); 187 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) 188 { 189 *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp] = mData; 190 } 191 else 192 { 193 mData = *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp]; 194 } 195 196 // Do the wait immediately. Note that doing the wait here eats almost 197 // all the performance anyway, so we only gain something if we're 198 // using temporal decoupling. 199 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 200 wait(dmi_data.first.get_write_latency()); 201 202 } else { 203 wait(dmi_data.first.get_read_latency()); 204 } 205 } 206 else // we need a full transaction 207 { 208 socket->b_transport(trans, t); 209 wait(t); 210 } 211 logEndTransaction(trans); 212 } 213 wait(); 214 215 } 216 217 // Invalidate DMI pointer(s) 218 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 219 sc_dt::uint64 end_range) 220 { 221 // FIXME: probably faster to always invalidate everything? 222 if (start_range <= mDMIDataReads.first.get_end_address ()&& 223 end_range >= mDMIDataReads.first.get_start_address()) { 224 mDMIDataReads.second = false; 225 } 226 if (start_range <= mDMIDataWrites.first.get_end_address ()&& 227 end_range >= mDMIDataWrites.first.get_start_address()) { 228 mDMIDataWrites.second = false; 229 } 230 } 231 232 // Test for transport_dbg, this one should fail in bus_dmi as we address 233 // a target that doesn't support transport_dbg: 234 // FIXME: use a configurable address 235 void end_of_simulation() 236 { 237 std::cout << name() << ", <<SimpleLTInitiator1>>:" << std::endl 238 << std::endl; 239 unsigned char data[32]; 240 241 transaction_type trans; 242 trans.set_address(mBaseAddress); 243 trans.set_data_length(32); 244 trans.set_data_ptr(data); 245 trans.set_read(); 246 247 unsigned int n = socket->transport_dbg(trans); 248 249 std::cout << "Mem @" << std::hex << mBaseAddress << std::endl; 250 unsigned int j = 0; 251 252 if (n > 0) 253 { 254 // always align endianness, so that we don't get a diff when 255 // printing the raw data 256 int e_start = 0; 257 int e_end = 4; 258 int e_increment = 1; 259 if (!tlm::host_has_little_endianness()) 260 { 261 e_start = 3; 262 e_end = -1; 263 e_increment = -1; 264 } 265 266 for (unsigned int i=0; i<n; i+=4) 267 { 268 for (int k=e_start; k!=e_end; k+=e_increment) 269 { 270 std::cout << std::setw(2) << std::setfill('0') 271 << (int)data[i+k]; 272 j++; 273 if (j==16) { 274 j=0; 275 std::cout << std::endl; 276 } else { 277 std::cout << " "; 278 } 279 } 280 } 281 } 282 else 283 { 284 std::cout << "OK: debug transaction didn't give data." << std::endl; 285 } 286 std::cout << std::dec << std::endl; 287 } 288private: 289 std::pair<dmi_type, bool> mDMIDataReads; 290 std::pair<dmi_type, bool> mDMIDataWrites; 291 292 sc_core::sc_event mEndEvent; 293 unsigned int mNrOfTransactions; 294 unsigned int mBaseAddress; 295 unsigned int mTransactionCount; 296 unsigned int mData; 297}; 298 299#endif 300