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_GP_H__
28#define __TLM_GP_H__
29
30#include <systemc>
31#include "tlm_core/tlm_2/tlm_generic_payload/tlm_array.h"
32
33namespace tlm {
34
35class
36tlm_generic_payload;
37
38class tlm_mm_interface {
39public:
40  virtual void free(tlm_generic_payload*) = 0;
41  virtual ~tlm_mm_interface() {}
42};
43
44//---------------------------------------------------------------------------
45// Classes and helper functions for the extension mechanism
46//---------------------------------------------------------------------------
47// Helper function:
48inline unsigned int max_num_extensions(bool increment=false)
49{
50    static unsigned int max_num = 0;
51    if (increment) ++max_num;
52    return max_num;
53}
54
55// This class can be used for storing pointers to the extension classes, used
56// in tlm_generic_payload:
57class tlm_extension_base
58{
59public:
60    virtual tlm_extension_base* clone() const = 0;
61    virtual void free() { delete this; }
62    virtual void copy_from(tlm_extension_base const &) = 0;
63protected:
64    virtual ~tlm_extension_base() {}
65    static unsigned int register_extension()
66    {
67        return (max_num_extensions(true) - 1);
68    };
69};
70
71// Base class for all extension classes, derive your extension class in
72// the following way:
73// class my_extension : public tlm_extension<my_extension> { ...
74// This triggers proper extension registration during C++ static
75// contruction time. my_extension::ID will hold the unique index in the
76// tlm_generic_payload::m_extensions array.
77template <typename T>
78class tlm_extension : public tlm_extension_base
79{
80public:
81    virtual tlm_extension_base* clone() const = 0;
82    virtual void copy_from(tlm_extension_base const &ext) = 0; //{assert(typeid(this)==typeid(ext)); assert(ID === ext.ID); assert(0);}
83    virtual ~tlm_extension() {}
84    const static unsigned int ID;
85};
86
87template <typename T>
88const
89unsigned int tlm_extension<T>::ID = tlm_extension_base::register_extension();
90
91//---------------------------------------------------------------------------
92// enumeration types
93//---------------------------------------------------------------------------
94enum tlm_command {
95    TLM_READ_COMMAND,
96    TLM_WRITE_COMMAND,
97    TLM_IGNORE_COMMAND
98};
99
100enum tlm_response_status {
101    TLM_OK_RESPONSE = 1,
102    TLM_INCOMPLETE_RESPONSE = 0,
103    TLM_GENERIC_ERROR_RESPONSE = -1,
104    TLM_ADDRESS_ERROR_RESPONSE = -2,
105    TLM_COMMAND_ERROR_RESPONSE = -3,
106    TLM_BURST_ERROR_RESPONSE = -4,
107    TLM_BYTE_ENABLE_ERROR_RESPONSE = -5
108};
109
110enum tlm_gp_option {
111    TLM_MIN_PAYLOAD,
112    TLM_FULL_PAYLOAD,
113    TLM_FULL_PAYLOAD_ACCEPTED
114};
115
116#define TLM_BYTE_DISABLED 0x0
117#define TLM_BYTE_ENABLED 0xff
118
119//---------------------------------------------------------------------------
120// The generic payload class:
121//---------------------------------------------------------------------------
122class tlm_generic_payload {
123
124public:
125    //---------------
126    // Constructors
127    //---------------
128
129    // Default constructor
130    tlm_generic_payload()
131        : m_address(0)
132        , m_command(TLM_IGNORE_COMMAND)
133        , m_data(0)
134        , m_length(0)
135        , m_response_status(TLM_INCOMPLETE_RESPONSE)
136        , m_dmi(false)
137        , m_byte_enable(0)
138        , m_byte_enable_length(0)
139        , m_streaming_width(0)
140        , m_gp_option(TLM_MIN_PAYLOAD)
141        , m_extensions(max_num_extensions())
142        , m_mm(0)
143        , m_ref_count(0)
144    {
145    }
146
147    explicit tlm_generic_payload(tlm_mm_interface* mm)
148        : m_address(0)
149        , m_command(TLM_IGNORE_COMMAND)
150        , m_data(0)
151        , m_length(0)
152        , m_response_status(TLM_INCOMPLETE_RESPONSE)
153        , m_dmi(false)
154        , m_byte_enable(0)
155        , m_byte_enable_length(0)
156        , m_streaming_width(0)
157        , m_gp_option(TLM_MIN_PAYLOAD)
158        , m_extensions(max_num_extensions())
159        , m_mm(mm)
160        , m_ref_count(0)
161    {
162    }
163
164    void acquire(){assert(m_mm != 0); m_ref_count++;}
165    void release(){assert(m_mm != 0 && m_ref_count > 0); if (--m_ref_count==0) m_mm->free(this);}
166    int get_ref_count() const {return m_ref_count;}
167    void set_mm(tlm_mm_interface* mm) { m_mm = mm; }
168    bool has_mm() const { return m_mm != 0; }
169
170    void reset(){
171      //should the other members be reset too?
172      m_gp_option = TLM_MIN_PAYLOAD;
173      m_extensions.free_entire_cache();
174    };
175
176
177private:
178    //disabled copy ctor and assignment operator.
179    // Copy constructor
180    tlm_generic_payload(const tlm_generic_payload& x)
181        : m_address(x.get_address())
182        , m_command(x.get_command())
183        , m_data(x.get_data_ptr())
184        , m_length(x.get_data_length())
185        , m_response_status(x.get_response_status())
186        , m_dmi(x.is_dmi_allowed())
187        , m_byte_enable(x.get_byte_enable_ptr())
188        , m_byte_enable_length(x.get_byte_enable_length())
189        , m_streaming_width(x.get_streaming_width())
190        , m_gp_option(x.m_gp_option)
191        , m_extensions(max_num_extensions())
192    {
193        // copy all extensions
194        for(unsigned int i=0; i<m_extensions.size(); i++)
195        {
196            m_extensions[i] = x.get_extension(i);
197        }
198    }
199
200    // Assignment operator
201    tlm_generic_payload& operator= (const tlm_generic_payload& x)
202    {
203        m_command =            x.get_command();
204        m_address =            x.get_address();
205        m_data =               x.get_data_ptr();
206        m_length =             x.get_data_length();
207        m_response_status =    x.get_response_status();
208        m_byte_enable =        x.get_byte_enable_ptr();
209        m_byte_enable_length = x.get_byte_enable_length();
210        m_streaming_width =    x.get_streaming_width();
211        m_gp_option =          x.get_gp_option();
212        m_dmi =                x.is_dmi_allowed();
213
214        // extension copy: all extension arrays must be of equal size by
215        // construction (i.e. it must either be constructed after C++
216        // static construction time, or the resize_extensions() method must
217        // have been called prior to using the object)
218        for(unsigned int i=0; i<m_extensions.size(); i++)
219        {
220            m_extensions[i] = x.get_extension(i);
221        }
222        return (*this);
223    }
224public:
225    // non-virtual deep-copying of the object
226    void deep_copy_from(const tlm_generic_payload & other)
227    {
228        m_command =            other.get_command();
229        m_address =            other.get_address();
230        m_length =             other.get_data_length();
231        m_response_status =    other.get_response_status();
232        m_byte_enable_length = other.get_byte_enable_length();
233        m_streaming_width =    other.get_streaming_width();
234        m_gp_option =          other.get_gp_option();
235        m_dmi =                other.is_dmi_allowed();
236
237        // deep copy data
238        // there must be enough space in the target transaction!
239        if(m_data && other.m_data)
240        {
241            memcpy(m_data, other.m_data, m_length);
242        }
243        // deep copy byte enables
244        // there must be enough space in the target transaction!
245        if(m_byte_enable && other.m_byte_enable)
246        {
247            memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length);
248        }
249        // deep copy extensions (sticky and non-sticky)
250        for(unsigned int i=0; i<other.m_extensions.size(); i++)
251        {
252            if(other.m_extensions[i])
253            {                       //original has extension i
254                if(!m_extensions[i])
255                {                   //We don't: clone.
256                    tlm_extension_base *ext = other.m_extensions[i]->clone();
257                    if(ext)     //extension may not be clonable.
258                    {
259                        if(has_mm())
260                        {           //mm can take care of removing cloned extensions
261                            set_auto_extension(i, ext);
262                        }
263                        else
264                        {           // no mm, user will call free_all_extensions().
265                            set_extension(i, ext);
266                        }
267                    }
268                }
269                else
270                {                   //We already have such extension. Copy original over it.
271                    m_extensions[i]->copy_from(*other.m_extensions[i]);
272                }
273            }
274        }
275    }
276
277    // To update the state of the original generic payload from a deep copy
278    // Assumes that "other" was created from the original by calling deep_copy_from
279    // Argument use_byte_enable_on_read determines whether to use or ignores byte enables
280    // when copying back the data array on a read command
281
282    void update_original_from(const tlm_generic_payload & other,
283                              bool use_byte_enable_on_read = true)
284    {
285        // Copy back extensions that are present on the original
286        update_extensions_from(other);
287
288        // Copy back the response status and DMI hint attributes
289        m_response_status = other.get_response_status();
290        m_dmi             = other.is_dmi_allowed();
291
292        // Copy back the data array for a read command only
293        // deep_copy_from allowed null pointers, and so will we
294        // We assume the arrays are the same size
295        // We test for equal pointers in case the original and the copy share the same array
296
297        if(is_read() && m_data && other.m_data && m_data != other.m_data)
298        {
299            if (m_byte_enable && use_byte_enable_on_read)
300            {
301                if (m_byte_enable_length == 8 && m_length % 8 == 0 )
302                {
303                    // Optimized implementation copies 64-bit words by masking
304                    for (unsigned int i = 0; i < m_length; i += 8)
305                    {
306                        typedef sc_dt::uint64* u;
307                        *reinterpret_cast<u>(&m_data[i]) &= ~*reinterpret_cast<u>(m_byte_enable);
308                        *reinterpret_cast<u>(&m_data[i]) |= *reinterpret_cast<u>(&other.m_data[i]) &
309                                                            *reinterpret_cast<u>(m_byte_enable);
310                    }
311                }
312                else if (m_byte_enable_length == 4 && m_length % 4 == 0 )
313                {
314                    // Optimized implementation copies 32-bit words by masking
315                    for (unsigned int i = 0; i < m_length; i += 4)
316                    {
317                        typedef unsigned int* u;
318                        *reinterpret_cast<u>(&m_data[i]) &= ~*reinterpret_cast<u>(m_byte_enable);
319                        *reinterpret_cast<u>(&m_data[i]) |= *reinterpret_cast<u>(&other.m_data[i]) &
320                                                            *reinterpret_cast<u>(m_byte_enable);
321                    }
322                }
323                else
324                    // Unoptimized implementation
325                    for (unsigned int i = 0; i < m_length; i++)
326                        if ( m_byte_enable[i % m_byte_enable_length] )
327                            m_data[i] = other.m_data[i];
328            }
329            else
330              memcpy(m_data, other.m_data, m_length);
331        }
332    }
333
334    void update_extensions_from(const tlm_generic_payload & other)
335    {
336        // deep copy extensions that are already present
337        for(unsigned int i=0; i<other.m_extensions.size(); i++)
338        {
339            if(other.m_extensions[i])
340            {                       //original has extension i
341                if(m_extensions[i])
342                {                   //We have it too. copy.
343                    m_extensions[i]->copy_from(*other.m_extensions[i]);
344                }
345            }
346        }
347    }
348
349    // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager.
350    // normal and sticky extensions are freed and extension array cleared.
351    void free_all_extensions()
352    {
353        m_extensions.free_entire_cache();
354        for(unsigned int i=0; i<m_extensions.size(); i++)
355        {
356            if(m_extensions[i])
357            {
358                m_extensions[i]->free();
359                m_extensions[i] = 0;
360            }
361        }
362    }
363    //--------------
364    // Destructor
365    //--------------
366    virtual ~tlm_generic_payload() {
367        for(unsigned int i=0; i<m_extensions.size(); i++)
368            if(m_extensions[i]) m_extensions[i]->free();
369    }
370
371    //----------------
372    // API (including setters & getters)
373    //---------------
374
375    // Command related method
376    bool                 is_read() const {return (m_command == TLM_READ_COMMAND);}
377    void                 set_read() {m_command = TLM_READ_COMMAND;}
378    bool                 is_write() const {return (m_command == TLM_WRITE_COMMAND);}
379    void                 set_write() {m_command = TLM_WRITE_COMMAND;}
380    tlm_command          get_command() const {return m_command;}
381    void                 set_command(const tlm_command command) {m_command = command;}
382
383    // Address related methods
384    sc_dt::uint64        get_address() const {return m_address;}
385    void                 set_address(const sc_dt::uint64 address) {m_address = address;}
386
387    // Data related methods
388    unsigned char*       get_data_ptr() const {return m_data;}
389    void                 set_data_ptr(unsigned char* data) {m_data = data;}
390
391    // Transaction length (in bytes) related methods
392    unsigned int         get_data_length() const {return m_length;}
393    void                 set_data_length(const unsigned int length) {m_length = length;}
394
395    // Response status related methods
396    bool                 is_response_ok() const {return (m_response_status > 0);}
397    bool                 is_response_error() const {return (m_response_status <= 0);}
398    tlm_response_status  get_response_status() const {return m_response_status;}
399    void                 set_response_status(const tlm_response_status response_status)
400        {m_response_status = response_status;}
401    std::string          get_response_string() const
402    {
403        switch(m_response_status)
404        {
405        case TLM_OK_RESPONSE:            return "TLM_OK_RESPONSE";
406        case TLM_INCOMPLETE_RESPONSE:    return "TLM_INCOMPLETE_RESPONSE";
407        case TLM_GENERIC_ERROR_RESPONSE: return "TLM_GENERIC_ERROR_RESPONSE";
408        case TLM_ADDRESS_ERROR_RESPONSE: return "TLM_ADDRESS_ERROR_RESPONSE";
409        case TLM_COMMAND_ERROR_RESPONSE: return "TLM_COMMAND_ERROR_RESPONSE";
410        case TLM_BURST_ERROR_RESPONSE:   return "TLM_BURST_ERROR_RESPONSE";
411        case TLM_BYTE_ENABLE_ERROR_RESPONSE: return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
412        }
413        return "TLM_UNKNOWN_RESPONSE";
414    }
415
416    // Streaming related methods
417    unsigned int         get_streaming_width() const {return m_streaming_width;}
418    void                 set_streaming_width(const unsigned int streaming_width) {m_streaming_width = streaming_width; }
419
420    // Byte enable related methods
421    unsigned char*       get_byte_enable_ptr() const {return m_byte_enable;}
422    void                 set_byte_enable_ptr(unsigned char* byte_enable){m_byte_enable = byte_enable;}
423    unsigned int         get_byte_enable_length() const {return m_byte_enable_length;}
424    void                 set_byte_enable_length(const unsigned int byte_enable_length){m_byte_enable_length = byte_enable_length;}
425
426    // This is the "DMI-hint" a slave can set this to true if it
427    // wants to indicate that a DMI request would be supported:
428    void                 set_dmi_allowed(bool dmi_allowed) { m_dmi = dmi_allowed; }
429    bool                 is_dmi_allowed() const { return m_dmi; }
430
431    // Use full set of attributes in DMI/debug?
432    tlm_gp_option get_gp_option() const { return m_gp_option; }
433    void          set_gp_option( const tlm_gp_option gp_opt ) { m_gp_option = gp_opt; }
434
435private:
436
437    /* --------------------------------------------------------------------- */
438    /* Generic Payload attributes:                                           */
439    /* --------------------------------------------------------------------- */
440    /* - m_command         : Type of transaction. Three values supported:    */
441    /*                       - TLM_WRITE_COMMAND                             */
442    /*                       - TLM_READ_COMMAND                              */
443    /*                       - TLM_IGNORE_COMMAND                            */
444    /* - m_address         : Transaction base address (byte-addressing).     */
445    /* - m_data            : When m_command = TLM_WRITE_COMMAND contains a   */
446    /*                       pointer to the data to be written in the target.*/
447    /*                       When m_command = TLM_READ_COMMAND contains a    */
448    /*                       pointer where to copy the data read from the    */
449    /*                       target.                                         */
450    /* - m_length          : Total number of bytes of the transaction.       */
451    /* - m_response_status : This attribute indicates whether an error has   */
452    /*                       occurred during the transaction.                */
453    /*                       Values supported are:                           */
454    /*                       - TLM_OK_RESP                                   */
455    /*                       - TLM_INCOMPLETE_RESP                           */
456    /*                       - TLM_GENERIC_ERROR_RESP                        */
457    /*                       - TLM_ADDRESS_ERROR_RESP                        */
458    /*                       - TLM_COMMAND_ERROR_RESP                        */
459    /*                       - TLM_BURST_ERROR_RESP                          */
460    /*                       - TLM_BYTE_ENABLE_ERROR_RESP                    */
461    /*                                                                       */
462    /* - m_byte_enable     : It can be used to create burst transfers where  */
463    /*                    the address increment between each beat is greater */
464    /*                    than the word length of each beat, or to place     */
465    /*                    words in selected byte lanes of a bus.             */
466    /* - m_byte_enable_length : For a read or a write command, the target    */
467    /*                    interpret the byte enable length attribute as the  */
468    /*                    number of elements in the bytes enable array.      */
469    /* - m_streaming_width  :                                                */
470    /* --------------------------------------------------------------------- */
471
472    sc_dt::uint64        m_address;
473    tlm_command          m_command;
474    unsigned char*       m_data;
475    unsigned int         m_length;
476    tlm_response_status  m_response_status;
477    bool                 m_dmi;
478    unsigned char*       m_byte_enable;
479    unsigned int         m_byte_enable_length;
480    unsigned int         m_streaming_width;
481    tlm_gp_option        m_gp_option;
482
483public:
484
485    /* --------------------------------------------------------------------- */
486    /* Dynamic extension mechanism:                                          */
487    /* --------------------------------------------------------------------- */
488    /* The extension mechanism is intended to enable initiator modules to    */
489    /* optionally and transparently add data fields to the                   */
490    /* tlm_generic_payload. Target modules are free to check for extensions  */
491    /* and may or may not react to the data in the extension fields. The     */
492    /* definition of the extensions' semantics is solely in the              */
493    /* responsibility of the user.                                           */
494    /*                                                                       */
495    /* The following rules apply:                                            */
496    /*                                                                       */
497    /* - Every extension class must be derived from tlm_extension, e.g.:     */
498    /*     class my_extension : public tlm_extension<my_extension> { ... }   */
499    /*                                                                       */
500    /* - A tlm_generic_payload object should be constructed after C++        */
501    /*   static initialization time. This way it is guaranteed that the      */
502    /*   extension array is of sufficient size to hold all possible          */
503    /*   extensions. Alternatively, the initiator module can enforce a valid */
504    /*   extension array size by calling the resize_extensions() method      */
505    /*   once before the first transaction with the payload object is        */
506    /*   initiated.                                                          */
507    /*                                                                       */
508    /* - Initiators should use the the set_extension(e) or clear_extension(e)*/
509    /*   methods for manipulating the extension array. The type of the       */
510    /*   argument must be a pointer to the specific registered extension     */
511    /*   type (my_extension in the above example) and is used to             */
512    /*   automatically locate the appropriate index in the array.            */
513    /*                                                                       */
514    /* - Targets can check for a specific extension by calling               */
515    /*   get_extension(e). e will point to zero if the extension is not      */
516    /*   present.                                                            */
517    /*                                                                       */
518    /* --------------------------------------------------------------------- */
519
520    // Stick the pointer to an extension into the vector, return the
521    // previous value:
522    template <typename T> T* set_extension(T* ext)
523    {
524        return static_cast<T*>(set_extension(T::ID, ext));
525    }
526
527    // non-templatized version with manual index:
528    tlm_extension_base* set_extension(unsigned int index,
529                                      tlm_extension_base* ext)
530    {
531        tlm_extension_base* tmp = m_extensions[index];
532        m_extensions[index] = ext;
533        return tmp;
534    }
535
536    // Stick the pointer to an extension into the vector, return the
537    // previous value and schedule its release
538    template <typename T> T* set_auto_extension(T* ext)
539    {
540        return static_cast<T*>(set_auto_extension(T::ID, ext));
541    }
542
543    // non-templatized version with manual index:
544    tlm_extension_base* set_auto_extension(unsigned int index,
545                                           tlm_extension_base* ext)
546    {
547        tlm_extension_base* tmp = m_extensions[index];
548        m_extensions[index] = ext;
549        if (!tmp) m_extensions.insert_in_cache(&m_extensions[index]);
550        assert(m_mm != 0);
551        return tmp;
552    }
553
554    // Check for an extension, ext will point to 0 if not present
555    template <typename T> void get_extension(T*& ext) const
556    {
557        ext = get_extension<T>();
558    }
559    template <typename T> T* get_extension() const
560    {
561        return static_cast<T*>(get_extension(T::ID));
562    }
563    // Non-templatized version with manual index:
564    tlm_extension_base* get_extension(unsigned int index) const
565    {
566        return m_extensions[index];
567    }
568
569    //this call just removes the extension from the txn but does not
570    // call free() or tells the MM to do so
571    // it return false if there was active MM so you are now in an unsafe situation
572    // recommended use: when 100% sure there is no MM
573    template <typename T> void clear_extension(const T* ext)
574    {
575        clear_extension<T>();
576    }
577
578    //this call just removes the extension from the txn but does not
579    // call free() or tells the MM to do so
580    // it return false if there was active MM so you are now in an unsafe situation
581    // recommended use: when 100% sure there is no MM
582    template <typename T> void clear_extension()
583    {
584        clear_extension(T::ID);
585    }
586
587    //this call removes the extension from the txn and does
588    // call free() or tells the MM to do so when the txn is finally done
589    // recommended use: when not sure there is no MM
590    template <typename T> void release_extension(T* ext)
591    {
592        release_extension<T>();
593    }
594
595    //this call removes the extension from the txn and does
596    // call free() or tells the MM to do so when the txn is finally done
597    // recommended use: when not sure there is no MM
598    template <typename T> void release_extension()
599    {
600        release_extension(T::ID);
601    }
602
603private:
604    // Non-templatized version with manual index
605    void clear_extension(unsigned int index)
606    {
607        m_extensions[index] = static_cast<tlm_extension_base*>(0);
608    }
609    // Non-templatized version with manual index
610    void release_extension(unsigned int index)
611    {
612        if (m_mm)
613        {
614            m_extensions.insert_in_cache(&m_extensions[index]);
615        }
616        else
617        {
618            m_extensions[index]->free();
619            m_extensions[index] = static_cast<tlm_extension_base*>(0);
620        }
621    }
622
623public:
624    // Make sure the extension array is large enough. Can be called once by
625    // an initiator module (before issuing the first transaction) to make
626    // sure that the extension array is of correct size. This is only needed
627    // if the initiator cannot guarantee that the generic payload object is
628    // allocated after C++ static construction time.
629    void resize_extensions()
630    {
631        m_extensions.expand(max_num_extensions());
632    }
633
634private:
635    tlm_array<tlm_extension_base*> m_extensions;
636    tlm_mm_interface*              m_mm;
637    unsigned int                   m_ref_count;
638};
639
640} // namespace tlm
641
642#endif /* __TLM_GP_H__ */
643