SimpleLTInitiator3_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_INITIATOR3_DMI_H__ 33#define __SIMPLE_LT_INITIATOR3_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 <map> 41 42class SimpleLTInitiator3_dmi : public sc_core::sc_module 43{ 44public: 45 typedef tlm::tlm_generic_payload transaction_type; 46 typedef tlm::tlm_dmi dmi_type; 47 typedef tlm::tlm_phase phase_type; 48 typedef tlm::tlm_sync_enum sync_enum_type; 49 typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator3_dmi> initiator_socket_type; 50 51public: 52 initiator_socket_type socket; 53 54public: 55 SC_HAS_PROCESS(SimpleLTInitiator3_dmi); 56 SimpleLTInitiator3_dmi(sc_core::sc_module_name name, 57 unsigned int nrOfTransactions = 0x5, 58 unsigned int baseAddress = 0x0) : 59 sc_core::sc_module(name), 60 socket("socket"), 61 mNrOfTransactions(nrOfTransactions), 62 mBaseAddress(baseAddress), 63 mTransactionCount(0) 64 { 65 mDMIDataReads.first.set_start_address(1); 66 mDMIDataReads.first.set_end_address(0); 67 mDMIDataWrites.first.set_start_address(1); 68 mDMIDataWrites.first.set_end_address(0); 69 70 socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator3_dmi::invalidate_direct_mem_ptr); 71 72 // Initiator thread 73 SC_THREAD(run); 74 } 75 76 bool initTransaction(transaction_type& trans) 77 { 78 if (mTransactionCount < mNrOfTransactions) { 79 trans.set_address(mBaseAddress + 4*mTransactionCount); 80 mData = mTransactionCount; 81 trans.set_command(tlm::TLM_WRITE_COMMAND); 82 83 } else if (mTransactionCount < 2 * mNrOfTransactions) { 84 trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions)); 85 mData = 0; 86 trans.set_command(tlm::TLM_READ_COMMAND); 87 88 } else { 89 return false; 90 } 91 92 trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData)); 93 trans.set_data_length(4); 94 trans.set_streaming_width(4); 95 trans.set_dmi_allowed(false); 96 trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); 97 98 ++mTransactionCount; 99 return true; 100 } 101 102 void logStartTransation(transaction_type& trans) 103 { 104 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 105 std::cout << name() << ": Send write request: A = 0x" 106 << std::hex << (unsigned int)trans.get_address() 107 << ", D = 0x" << mData << std::dec 108 << " @ " << sc_core::sc_time_stamp() << std::endl; 109 110 } else { 111 std::cout << name() << ": Send read request: A = 0x" 112 << std::hex << (unsigned int)trans.get_address() << std::dec 113 << " @ " << sc_core::sc_time_stamp() << std::endl; 114 } 115 } 116 117 void logEndTransaction(transaction_type& trans) 118 { 119 if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) { 120 std::cout << name() << ": Received error response @ " 121 << sc_core::sc_time_stamp() << std::endl; 122 123 } else { 124 std::cout << name() << ": Received ok response"; 125 if (trans.get_command() == tlm::TLM_READ_COMMAND) { 126 std::cout << ": D = 0x" << std::hex << mData << std::dec; 127 } 128 std::cout << " @ " << sc_core::sc_time_stamp() << std::endl; 129 } 130 } 131 132 std::pair<dmi_type, bool>& getDMIData(const transaction_type& trans) 133 { 134 if (trans.get_command() == tlm::TLM_READ_COMMAND) { 135 return mDMIDataReads; 136 137 } else { // WRITE 138 return mDMIDataWrites; 139 } 140 } 141 142 void run() 143 { 144 transaction_type trans; 145 sc_core::sc_time t; 146 147 while (initTransaction(trans)) { 148 // Create transaction and initialise t 149 t = sc_core::SC_ZERO_TIME; 150 151 logStartTransation(trans); 152 153 /////////////////////////////////////////////////////////// 154 // DMI handling: 155 // We do *not* use the DMI hint to check if it makes sense to ask for 156 // DMI pointers. So the pattern is: 157 // - if the address is not covered by a DMI region try to acquire DMI 158 // pointers 159 // - if we have a DMI pointer, do the DMI "transaction" 160 // - otherwise fall back to a normal transaction 161 /////////////////////////////////////////////////////////// 162 163 std::pair<dmi_type, bool>& dmi_data = getDMIData(trans); 164 165 // Check if we need to acquire a DMI pointer 166 if((trans.get_address() < dmi_data.first.get_start_address()) || 167 (trans.get_address() > dmi_data.first.get_end_address()) ) 168 { 169 sc_dt::uint64 address = trans.get_address(); //save original address 170 dmi_data.second = 171 socket->get_direct_mem_ptr(trans, 172 dmi_data.first); 173 trans.set_address(address); 174 } 175 // Do DMI "transaction" if we have a valid region 176 if (dmi_data.second && 177 (trans.get_address() >= dmi_data.first.get_start_address()) && 178 (trans.get_address() <= dmi_data.first.get_end_address()) ) 179 { 180 // We can handle the data here. As the logEndTransaction is assuming 181 // something to happen in the data structure, we really need to 182 // do this: 183 trans.set_response_status(tlm::TLM_OK_RESPONSE); 184 185 sc_dt::uint64 tmp = trans.get_address() - dmi_data.first.get_start_address(); 186 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) 187 { 188 *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp] = mData; 189 } 190 else 191 { 192 mData = *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp]; 193 } 194 195 // Do the wait immediately. Note that doing the wait here eats almost 196 // all the performance anyway, so we only gain something if we're 197 // using temporal decoupling. 198 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 199 wait(dmi_data.first.get_write_latency()); 200 201 } else { 202 wait(dmi_data.first.get_read_latency()); 203 } 204 } 205 else // we need a full transaction 206 { 207 socket->b_transport(trans, t); 208 // wait for the returned delay 209 wait(t); 210 } 211 212 logEndTransaction(trans); 213 } 214 wait(); 215 216 } 217 218 // Invalidate DMI pointer(s) 219 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 220 sc_dt::uint64 end_range) 221 { 222 // FIXME: probably faster to always invalidate everything? 223 if (start_range <= mDMIDataReads.first.get_end_address ()&& 224 end_range >= mDMIDataReads.first.get_start_address()) { 225 mDMIDataReads.second = false; 226 } 227 if (start_range <= mDMIDataWrites.first.get_end_address ()&& 228 end_range >= mDMIDataWrites.first.get_start_address()) { 229 mDMIDataWrites.second = false; 230 } 231 } 232 233private: 234 std::pair<dmi_type, bool> mDMIDataReads; 235 std::pair<dmi_type, bool> mDMIDataWrites; 236 237 sc_core::sc_event mEndEvent; 238 unsigned int mNrOfTransactions; 239 unsigned int mBaseAddress; 240 unsigned int mTransactionCount; 241 unsigned int mData; 242}; 243 244#endif 245