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 // 12-Jan-2009  John Aynsley  Bug fix. has_mm() and get_ref_count() should both be const
21 // 23-Mar-2009  John Aynsley  Add method update_original_from()
22 // 20-Apr-2009  John Aynsley  Bug fix for 64-bit machines: unsigned long int -> unsigned int
23 //  5-May-2011  JA and Philipp Hartmann  Add tlm_gp_option, set_gp_option, get_gp_option
24 // 11-May-2011  John Aynsley  Add run-time check to release()
25 
26 
27 #ifndef TLM_CORE_TLM2_TLM_GP_H_INCLUDED_
28 #define TLM_CORE_TLM2_TLM_GP_H_INCLUDED_
29 
30 #include "sysc/kernel/sc_cmnhdr.h" // SC_API
31 #include "sysc/utils/sc_report.h" // sc_assert
32 #include "sysc/datatypes/int/sc_nbdefs.h" // sc_dt::uint64
33 
34 #include "tlm_core/tlm_2/tlm_generic_payload/tlm_array.h"
35 
36 #include <typeinfo> // std::type_info
37 
38 namespace tlm {
39 
40 class tlm_generic_payload;
41 
42 class tlm_mm_interface {
43 public:
44   virtual void free(tlm_generic_payload*) = 0;
~tlm_mm_interface()45   virtual ~tlm_mm_interface() {}
46 };
47 
48 //---------------------------------------------------------------------------
49 // Classes and helpers for the extension mechanism
50 //---------------------------------------------------------------------------
51 // Helper function:
52 SC_API unsigned int max_num_extensions();
53 
54 // This class can be used for storing pointers to the extension classes, used
55 // in tlm_generic_payload:
56 class SC_API tlm_extension_base
57 {
58 public:
59     virtual tlm_extension_base* clone() const = 0;
free()60     virtual void free() { delete this; }
61     virtual void copy_from(tlm_extension_base const &) = 0;
62 protected:
~tlm_extension_base()63     virtual ~tlm_extension_base() {}
64     static unsigned int register_extension(const std::type_info&);
65 };
66 
67 // Base class for all extension classes, derive your extension class in
68 // the following way:
69 // class my_extension : public tlm_extension<my_extension> { ...
70 // This triggers proper extension registration during C++ static
71 // contruction time. my_extension::ID will hold the unique index in the
72 // tlm_generic_payload::m_extensions array.
73 template <typename T>
74 class tlm_extension : public tlm_extension_base
75 {
76 public:
77     virtual tlm_extension_base* clone() const = 0;
78     virtual void copy_from(tlm_extension_base const &ext) = 0;
~tlm_extension()79     virtual ~tlm_extension() {}
80     const static unsigned int ID;
81 };
82 
83 template <typename T>
84 const unsigned int tlm_extension<T>::ID
85   = tlm_extension_base::register_extension(typeid(T));
86 
87 //---------------------------------------------------------------------------
88 // enumeration types
89 //---------------------------------------------------------------------------
90 enum tlm_command {
91     TLM_READ_COMMAND,
92     TLM_WRITE_COMMAND,
93     TLM_IGNORE_COMMAND
94 };
95 
96 enum tlm_response_status {
97     TLM_OK_RESPONSE = 1,
98     TLM_INCOMPLETE_RESPONSE = 0,
99     TLM_GENERIC_ERROR_RESPONSE = -1,
100     TLM_ADDRESS_ERROR_RESPONSE = -2,
101     TLM_COMMAND_ERROR_RESPONSE = -3,
102     TLM_BURST_ERROR_RESPONSE = -4,
103     TLM_BYTE_ENABLE_ERROR_RESPONSE = -5
104 };
105 
106 enum tlm_gp_option {
107     TLM_MIN_PAYLOAD,
108     TLM_FULL_PAYLOAD,
109     TLM_FULL_PAYLOAD_ACCEPTED
110 };
111 
112 #define TLM_BYTE_DISABLED 0x0
113 #define TLM_BYTE_ENABLED 0xff
114 
115 //---------------------------------------------------------------------------
116 // The generic payload class:
117 //---------------------------------------------------------------------------
118 
119 SC_API_TEMPLATE_DECL_ tlm_array<tlm_extension_base*>;
120 
121 class SC_API tlm_generic_payload {
122 
123 public:
124     //---------------
125     // Constructors
126     //---------------
127 
128     // Default constructor
129     tlm_generic_payload();
130     explicit tlm_generic_payload(tlm_mm_interface* mm);
131 
acquire()132     void acquire() { sc_assert(m_mm != 0); m_ref_count++; }
133 
release()134     void release() {
135         sc_assert(m_mm != 0 && m_ref_count > 0);
136         if (--m_ref_count==0)
137             m_mm->free(this);
138     }
139 
get_ref_count()140     int get_ref_count() const { return m_ref_count; }
141 
set_mm(tlm_mm_interface * mm)142     void set_mm(tlm_mm_interface* mm) { m_mm = mm; }
has_mm()143     bool has_mm() const { return m_mm != 0; }
144 
145     void reset();
146 
147 private:
148     //disabled copy ctor and assignment operator.
149     tlm_generic_payload(const tlm_generic_payload& x) /* = delete */;
150     tlm_generic_payload& operator= (const tlm_generic_payload& x) /* = delete */;
151 
152 public:
153     // non-virtual deep-copying of the object
154     void deep_copy_from(const tlm_generic_payload & other);
155 
156     // To update the state of the original generic payload from a deep copy
157     // Assumes that "other" was created from the original by calling deep_copy_from
158     // Argument use_byte_enable_on_read determines whether to use or ignores byte enables
159     // when copying back the data array on a read command
160 
161     void update_original_from(const tlm_generic_payload & other,
162                               bool use_byte_enable_on_read = true);
163 
164     void update_extensions_from(const tlm_generic_payload & other);
165 
166     // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager.
167     // normal and sticky extensions are freed and extension array cleared.
168     void free_all_extensions();
169 
170     //--------------
171     // Destructor
172     //--------------
173     virtual ~tlm_generic_payload();
174 
175     //----------------
176     // API (including setters & getters)
177     //---------------
178 
179     // Command related method
is_read()180     bool                 is_read() const {return (m_command == TLM_READ_COMMAND);}
set_read()181     void                 set_read() {m_command = TLM_READ_COMMAND;}
is_write()182     bool                 is_write() const {return (m_command == TLM_WRITE_COMMAND);}
set_write()183     void                 set_write() {m_command = TLM_WRITE_COMMAND;}
get_command()184     tlm_command          get_command() const {return m_command;}
set_command(const tlm_command command)185     void                 set_command(const tlm_command command) {m_command = command;}
186 
187     // Address related methods
get_address()188     sc_dt::uint64        get_address() const {return m_address;}
set_address(const sc_dt::uint64 address)189     void                 set_address(const sc_dt::uint64 address) {m_address = address;}
190 
191     // Data related methods
get_data_ptr()192     unsigned char*       get_data_ptr() const {return m_data;}
set_data_ptr(unsigned char * data)193     void                 set_data_ptr(unsigned char* data) {m_data = data;}
194 
195     // Transaction length (in bytes) related methods
get_data_length()196     unsigned int         get_data_length() const {return m_length;}
set_data_length(const unsigned int length)197     void                 set_data_length(const unsigned int length) {m_length = length;}
198 
199     // Response status related methods
is_response_ok()200     bool                 is_response_ok() const {return (m_response_status > 0);}
is_response_error()201     bool                 is_response_error() const {return (m_response_status <= 0);}
get_response_status()202     tlm_response_status  get_response_status() const {return m_response_status;}
set_response_status(const tlm_response_status response_status)203     void                 set_response_status(const tlm_response_status response_status)
204         {m_response_status = response_status;}
205     std::string          get_response_string() const;
206 
207     // Streaming related methods
get_streaming_width()208     unsigned int         get_streaming_width() const {return m_streaming_width;}
set_streaming_width(const unsigned int streaming_width)209     void                 set_streaming_width(const unsigned int streaming_width) {m_streaming_width = streaming_width; }
210 
211     // Byte enable related methods
get_byte_enable_ptr()212     unsigned char*       get_byte_enable_ptr() const {return m_byte_enable;}
set_byte_enable_ptr(unsigned char * byte_enable)213     void                 set_byte_enable_ptr(unsigned char* byte_enable){m_byte_enable = byte_enable;}
get_byte_enable_length()214     unsigned int         get_byte_enable_length() const {return m_byte_enable_length;}
set_byte_enable_length(const unsigned int byte_enable_length)215     void                 set_byte_enable_length(const unsigned int byte_enable_length){m_byte_enable_length = byte_enable_length;}
216 
217     // This is the "DMI-hint" a slave can set this to true if it
218     // wants to indicate that a DMI request would be supported:
set_dmi_allowed(bool dmi_allowed)219     void                 set_dmi_allowed(bool dmi_allowed) { m_dmi = dmi_allowed; }
is_dmi_allowed()220     bool                 is_dmi_allowed() const { return m_dmi; }
221 
222     // Use full set of attributes in DMI/debug?
get_gp_option()223     tlm_gp_option get_gp_option() const { return m_gp_option; }
set_gp_option(const tlm_gp_option gp_opt)224     void          set_gp_option( const tlm_gp_option gp_opt ) { m_gp_option = gp_opt; }
225 
226 private:
227 
228     /* --------------------------------------------------------------------- */
229     /* Generic Payload attributes:                                           */
230     /* --------------------------------------------------------------------- */
231     /* - m_command         : Type of transaction. Three values supported:    */
232     /*                       - TLM_WRITE_COMMAND                             */
233     /*                       - TLM_READ_COMMAND                              */
234     /*                       - TLM_IGNORE_COMMAND                            */
235     /* - m_address         : Transaction base address (byte-addressing).     */
236     /* - m_data            : When m_command = TLM_WRITE_COMMAND contains a   */
237     /*                       pointer to the data to be written in the target.*/
238     /*                       When m_command = TLM_READ_COMMAND contains a    */
239     /*                       pointer where to copy the data read from the    */
240     /*                       target.                                         */
241     /* - m_length          : Total number of bytes of the transaction.       */
242     /* - m_response_status : This attribute indicates whether an error has   */
243     /*                       occurred during the transaction.                */
244     /*                       Values supported are:                           */
245     /*                       - TLM_OK_RESP                                   */
246     /*                       - TLM_INCOMPLETE_RESP                           */
247     /*                       - TLM_GENERIC_ERROR_RESP                        */
248     /*                       - TLM_ADDRESS_ERROR_RESP                        */
249     /*                       - TLM_COMMAND_ERROR_RESP                        */
250     /*                       - TLM_BURST_ERROR_RESP                          */
251     /*                       - TLM_BYTE_ENABLE_ERROR_RESP                    */
252     /*                                                                       */
253     /* - m_byte_enable     : It can be used to create burst transfers where  */
254     /*                    the address increment between each beat is greater */
255     /*                    than the word length of each beat, or to place     */
256     /*                    words in selected byte lanes of a bus.             */
257     /* - m_byte_enable_length : For a read or a write command, the target    */
258     /*                    interpret the byte enable length attribute as the  */
259     /*                    number of elements in the bytes enable array.      */
260     /* - m_streaming_width  :                                                */
261     /* --------------------------------------------------------------------- */
262 
263     sc_dt::uint64        m_address;
264     tlm_command          m_command;
265     unsigned char*       m_data;
266     unsigned int         m_length;
267     tlm_response_status  m_response_status;
268     bool                 m_dmi;
269     unsigned char*       m_byte_enable;
270     unsigned int         m_byte_enable_length;
271     unsigned int         m_streaming_width;
272     tlm_gp_option        m_gp_option;
273 
274 public:
275 
276     /* --------------------------------------------------------------------- */
277     /* Dynamic extension mechanism:                                          */
278     /* --------------------------------------------------------------------- */
279     /* The extension mechanism is intended to enable initiator modules to    */
280     /* optionally and transparently add data fields to the                   */
281     /* tlm_generic_payload. Target modules are free to check for extensions  */
282     /* and may or may not react to the data in the extension fields. The     */
283     /* definition of the extensions' semantics is solely in the              */
284     /* responsibility of the user.                                           */
285     /*                                                                       */
286     /* The following rules apply:                                            */
287     /*                                                                       */
288     /* - Every extension class must be derived from tlm_extension, e.g.:     */
289     /*     class my_extension : public tlm_extension<my_extension> { ... }   */
290     /*                                                                       */
291     /* - A tlm_generic_payload object should be constructed after C++        */
292     /*   static initialization time. This way it is guaranteed that the      */
293     /*   extension array is of sufficient size to hold all possible          */
294     /*   extensions. Alternatively, the initiator module can enforce a valid */
295     /*   extension array size by calling the resize_extensions() method      */
296     /*   once before the first transaction with the payload object is        */
297     /*   initiated.                                                          */
298     /*                                                                       */
299     /* - Initiators should use the the set_extension(e) or clear_extension(e)*/
300     /*   methods for manipulating the extension array. The type of the       */
301     /*   argument must be a pointer to the specific registered extension     */
302     /*   type (my_extension in the above example) and is used to             */
303     /*   automatically locate the appropriate index in the array.            */
304     /*                                                                       */
305     /* - Targets can check for a specific extension by calling               */
306     /*   get_extension(e). e will point to zero if the extension is not      */
307     /*   present.                                                            */
308     /*                                                                       */
309     /* --------------------------------------------------------------------- */
310 
311     // Stick the pointer to an extension into the vector, return the
312     // previous value:
set_extension(T * ext)313     template <typename T> T* set_extension(T* ext)
314     {
315         return static_cast<T*>(set_extension(T::ID, ext));
316     }
317 
318     // non-templatized version with manual index:
319     tlm_extension_base* set_extension(unsigned int index,
320                                       tlm_extension_base* ext);
321 
322     // Stick the pointer to an extension into the vector, return the
323     // previous value and schedule its release
set_auto_extension(T * ext)324     template <typename T> T* set_auto_extension(T* ext)
325     {
326         return static_cast<T*>(set_auto_extension(T::ID, ext));
327     }
328 
329     // non-templatized version with manual index:
330     tlm_extension_base* set_auto_extension(unsigned int index,
331                                            tlm_extension_base* ext);
332 
333     // Check for an extension, ext will point to 0 if not present
get_extension(T * & ext)334     template <typename T> void get_extension(T*& ext) const
335     {
336         ext = get_extension<T>();
337     }
get_extension()338     template <typename T> T* get_extension() const
339     {
340         return static_cast<T*>(get_extension(T::ID));
341     }
342     // Non-templatized version with manual index:
343     tlm_extension_base* get_extension(unsigned int index) const;
344 
345     //this call just removes the extension from the txn but does not
346     // call free() or tells the MM to do so
347     // it return false if there was active MM so you are now in an unsafe situation
348     // recommended use: when 100% sure there is no MM
clear_extension(const T * ext)349     template <typename T> void clear_extension(const T* ext)
350     {
351         clear_extension<T>();
352     }
353 
354     //this call just removes the extension from the txn but does not
355     // call free() or tells the MM to do so
356     // it return false if there was active MM so you are now in an unsafe situation
357     // recommended use: when 100% sure there is no MM
clear_extension()358     template <typename T> void clear_extension()
359     {
360         clear_extension(T::ID);
361     }
362 
363     //this call removes the extension from the txn and does
364     // call free() or tells the MM to do so when the txn is finally done
365     // recommended use: when not sure there is no MM
release_extension(T * ext)366     template <typename T> void release_extension(T* ext)
367     {
368         release_extension<T>();
369     }
370 
371     //this call removes the extension from the txn and does
372     // call free() or tells the MM to do so when the txn is finally done
373     // recommended use: when not sure there is no MM
release_extension()374     template <typename T> void release_extension()
375     {
376         release_extension(T::ID);
377     }
378 
379 private:
380     // Non-templatized version with manual index
381     void clear_extension(unsigned int index);
382     // Non-templatized version with manual index
383     void release_extension(unsigned int index);
384 
385 public:
386     // Make sure the extension array is large enough. Can be called once by
387     // an initiator module (before issuing the first transaction) to make
388     // sure that the extension array is of correct size. This is only needed
389     // if the initiator cannot guarantee that the generic payload object is
390     // allocated after C++ static construction time.
391     void resize_extensions();
392 
393 private:
394     tlm_array<tlm_extension_base*> m_extensions;
395     tlm_mm_interface*              m_mm;
396     unsigned int                   m_ref_count;
397 };
398 
399 } // namespace tlm
400 
401 
402 #endif /* TLM_CORE_TLM2_TLM_GP_H_INCLUDED_ */
403