SimpleLTInitiator2_DMI.h revision 12922
110298Salexandru.dutu@amd.com/***************************************************************************** 210298Salexandru.dutu@amd.com 310298Salexandru.dutu@amd.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 410298Salexandru.dutu@amd.com more contributor license agreements. See the NOTICE file distributed 510298Salexandru.dutu@amd.com with this work for additional information regarding copyright ownership. 610298Salexandru.dutu@amd.com Accellera licenses this file to you under the Apache License, Version 2.0 710298Salexandru.dutu@amd.com (the "License"); you may not use this file except in compliance with the 810298Salexandru.dutu@amd.com License. You may obtain a copy of the License at 910298Salexandru.dutu@amd.com 1010298Salexandru.dutu@amd.com http://www.apache.org/licenses/LICENSE-2.0 1110298Salexandru.dutu@amd.com 1210298Salexandru.dutu@amd.com Unless required by applicable law or agreed to in writing, software 1310298Salexandru.dutu@amd.com distributed under the License is distributed on an "AS IS" BASIS, 1410298Salexandru.dutu@amd.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1510298Salexandru.dutu@amd.com implied. See the License for the specific language governing 1610298Salexandru.dutu@amd.com permissions and limitations under the License. 1710298Salexandru.dutu@amd.com 1810298Salexandru.dutu@amd.com *****************************************************************************/ 1910298Salexandru.dutu@amd.com 2010298Salexandru.dutu@amd.com//==================================================================== 2110298Salexandru.dutu@amd.com// Nov 06, 2008 2210298Salexandru.dutu@amd.com// 2310298Salexandru.dutu@amd.com// Updated by: 2410298Salexandru.dutu@amd.com// Xiaopeng Qiu, JEDA Technologies, Inc 2510298Salexandru.dutu@amd.com// Email: qiuxp@jedatechnologies.net 2610298Salexandru.dutu@amd.com// 2710298Salexandru.dutu@amd.com// To fix violations of TLM2.0 rules, which are detected by JEDA 2810298Salexandru.dutu@amd.com// TLM2.0 checker. 2910298Salexandru.dutu@amd.com// 3010298Salexandru.dutu@amd.com//==================================================================== 3110298Salexandru.dutu@amd.com 3210298Salexandru.dutu@amd.com#ifndef __SIMPLE_LT_INITIATOR2_DMI_H__ 3310298Salexandru.dutu@amd.com#define __SIMPLE_LT_INITIATOR2_DMI_H__ 3410298Salexandru.dutu@amd.com 3510298Salexandru.dutu@amd.com#include "tlm.h" 3610298Salexandru.dutu@amd.com#include "tlm_utils/simple_initiator_socket.h" 3710298Salexandru.dutu@amd.com#include <systemc> 3810298Salexandru.dutu@amd.com#include <cassert> 3910298Salexandru.dutu@amd.com#include <iostream> 4010298Salexandru.dutu@amd.com#include <iomanip> 4110298Salexandru.dutu@amd.com#include <map> 4210298Salexandru.dutu@amd.com 4310298Salexandru.dutu@amd.comclass SimpleLTInitiator2_dmi : public sc_core::sc_module 4411800Sbrandon.potter@amd.com{ 4511800Sbrandon.potter@amd.compublic: 4610298Salexandru.dutu@amd.com typedef tlm::tlm_generic_payload transaction_type; 4710298Salexandru.dutu@amd.com typedef tlm::tlm_dmi dmi_type; 4810298Salexandru.dutu@amd.com typedef tlm::tlm_phase phase_type; 4910298Salexandru.dutu@amd.com typedef tlm::tlm_sync_enum sync_enum_type; 5010298Salexandru.dutu@amd.com typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator2_dmi> initiator_socket_type; 5110298Salexandru.dutu@amd.com 5210298Salexandru.dutu@amd.compublic: 5310298Salexandru.dutu@amd.com initiator_socket_type socket; 5410298Salexandru.dutu@amd.com 5510298Salexandru.dutu@amd.compublic: 5610298Salexandru.dutu@amd.com SC_HAS_PROCESS(SimpleLTInitiator2_dmi); 5710298Salexandru.dutu@amd.com SimpleLTInitiator2_dmi(sc_core::sc_module_name name, 5810298Salexandru.dutu@amd.com unsigned int nrOfTransactions = 0x5, 5910298Salexandru.dutu@amd.com unsigned int baseAddress = 0x0) : 6010298Salexandru.dutu@amd.com sc_core::sc_module(name), 6110298Salexandru.dutu@amd.com socket("socket"), 6210298Salexandru.dutu@amd.com mNrOfTransactions(nrOfTransactions), 6310298Salexandru.dutu@amd.com mBaseAddress(baseAddress), 6410298Salexandru.dutu@amd.com mTransactionCount(0) 6510298Salexandru.dutu@amd.com { 6610298Salexandru.dutu@amd.com mDMIDataReads.first.set_start_address(1); 6710298Salexandru.dutu@amd.com mDMIDataReads.first.set_end_address(0); 6810298Salexandru.dutu@amd.com mDMIDataWrites.first.set_start_address(1); 6910298Salexandru.dutu@amd.com mDMIDataWrites.first.set_end_address(0); 7010298Salexandru.dutu@amd.com 7110298Salexandru.dutu@amd.com // register invalidate method 7210298Salexandru.dutu@amd.com socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator2_dmi::invalidate_direct_mem_ptr); 7310298Salexandru.dutu@amd.com 7410298Salexandru.dutu@amd.com // Initiator thread 7510298Salexandru.dutu@amd.com SC_THREAD(run); 7610298Salexandru.dutu@amd.com } 7710298Salexandru.dutu@amd.com 7810298Salexandru.dutu@amd.com bool initTransaction(transaction_type& trans) 7910298Salexandru.dutu@amd.com { 8010298Salexandru.dutu@amd.com if (mTransactionCount < mNrOfTransactions) { 8110298Salexandru.dutu@amd.com trans.set_address(mBaseAddress + 4*mTransactionCount); 8210298Salexandru.dutu@amd.com mData = mTransactionCount; 8310298Salexandru.dutu@amd.com trans.set_command(tlm::TLM_WRITE_COMMAND); 8410298Salexandru.dutu@amd.com 8510298Salexandru.dutu@amd.com } else if (mTransactionCount < 2 * mNrOfTransactions) { 8610298Salexandru.dutu@amd.com trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions)); 8710298Salexandru.dutu@amd.com mData = 0; 8810298Salexandru.dutu@amd.com trans.set_command(tlm::TLM_READ_COMMAND); 8910298Salexandru.dutu@amd.com 9010298Salexandru.dutu@amd.com } else { 9110298Salexandru.dutu@amd.com return false; 9210298Salexandru.dutu@amd.com } 9310298Salexandru.dutu@amd.com 9410298Salexandru.dutu@amd.com trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData)); 9510298Salexandru.dutu@amd.com trans.set_data_length(4); 9610298Salexandru.dutu@amd.com trans.set_streaming_width(4); 9710298Salexandru.dutu@amd.com trans.set_dmi_allowed(false); 9810298Salexandru.dutu@amd.com trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); 9910298Salexandru.dutu@amd.com 10010298Salexandru.dutu@amd.com ++mTransactionCount; 10110298Salexandru.dutu@amd.com return true; 10210298Salexandru.dutu@amd.com } 10312448Sgabeblack@google.com 10410298Salexandru.dutu@amd.com void logStartTransation(transaction_type& trans) 10510298Salexandru.dutu@amd.com { 10610298Salexandru.dutu@amd.com if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 10710298Salexandru.dutu@amd.com std::cout << name() << ": Send write request: A = 0x" 10810298Salexandru.dutu@amd.com << std::hex << (unsigned int)trans.get_address() 10910298Salexandru.dutu@amd.com << ", D = 0x" << mData << std::dec 11010298Salexandru.dutu@amd.com << " @ " << sc_core::sc_time_stamp() << std::endl; 11110298Salexandru.dutu@amd.com 11210298Salexandru.dutu@amd.com } else { 11310298Salexandru.dutu@amd.com std::cout << name() << ": Send read request: A = 0x" 11410298Salexandru.dutu@amd.com << std::hex << (unsigned int)trans.get_address() << std::dec 11510298Salexandru.dutu@amd.com << " @ " << sc_core::sc_time_stamp() << std::endl; 11610298Salexandru.dutu@amd.com } 11710298Salexandru.dutu@amd.com } 11810298Salexandru.dutu@amd.com 11910298Salexandru.dutu@amd.com void logEndTransaction(transaction_type& trans) 12010298Salexandru.dutu@amd.com { 12110298Salexandru.dutu@amd.com if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) { 12210298Salexandru.dutu@amd.com std::cout << name() << ": Received error response @ " 12310298Salexandru.dutu@amd.com << sc_core::sc_time_stamp() << std::endl; 12410298Salexandru.dutu@amd.com 12510298Salexandru.dutu@amd.com } else { 12610298Salexandru.dutu@amd.com std::cout << name() << ": Received ok response"; 12710298Salexandru.dutu@amd.com if (trans.get_command() == tlm::TLM_READ_COMMAND) { 12810298Salexandru.dutu@amd.com std::cout << ": D = 0x" << std::hex << mData << std::dec; 12910298Salexandru.dutu@amd.com } 13010298Salexandru.dutu@amd.com std::cout << " @ " << sc_core::sc_time_stamp() << std::endl; 13110298Salexandru.dutu@amd.com } 13210298Salexandru.dutu@amd.com } 13310298Salexandru.dutu@amd.com 13410298Salexandru.dutu@amd.com std::pair<dmi_type, bool>& getDMIData(const transaction_type& trans) 13510298Salexandru.dutu@amd.com { 13610298Salexandru.dutu@amd.com if (trans.get_command() == tlm::TLM_READ_COMMAND) { 13710298Salexandru.dutu@amd.com return mDMIDataReads; 13812446Sgabeblack@google.com 13910298Salexandru.dutu@amd.com } else { // WRITE 14010298Salexandru.dutu@amd.com return mDMIDataWrites; 14110556Salexandru.dutu@amd.com } 14212432Sgabeblack@google.com } 14310298Salexandru.dutu@amd.com 14410298Salexandru.dutu@amd.com void run() 14511175Sandreas.hansson@arm.com { 14610298Salexandru.dutu@amd.com transaction_type trans; 14710558Salexandru.dutu@amd.com sc_core::sc_time t; 14811175Sandreas.hansson@arm.com 14911175Sandreas.hansson@arm.com while (initTransaction(trans)) { 15011175Sandreas.hansson@arm.com // Create transaction and initialise t 15111168Sandreas.hansson@arm.com t = sc_core::SC_ZERO_TIME; 15211168Sandreas.hansson@arm.com 15310298Salexandru.dutu@amd.com logStartTransation(trans); 15410298Salexandru.dutu@amd.com 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