From 7364acfc758a30f81aa75844f6b96b1e4e19990a Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 8 Dec 2018 01:58:26 -0800 Subject: systemc: Initial import of TLM headers from Accellera. These headers will need to be cleaned up and have some Accellera specific quirks ironed out of them, but I'll do that in a later change to make it clear what those changes are. Change-Id: Ia4e08633ab552b4c616c66c9b7e2bbd78ebfe7b9 Reviewed-on: https://gem5-review.googlesource.com/c/15055 Reviewed-by: Anthony Gutierrez Maintainer: Anthony Gutierrez --- src/systemc/ext/tlm_utils/peq_with_cb_and_phase.h | 301 ++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 src/systemc/ext/tlm_utils/peq_with_cb_and_phase.h (limited to 'src/systemc/ext/tlm_utils/peq_with_cb_and_phase.h') diff --git a/src/systemc/ext/tlm_utils/peq_with_cb_and_phase.h b/src/systemc/ext/tlm_utils/peq_with_cb_and_phase.h new file mode 100644 index 000000000..60f96e6bd --- /dev/null +++ b/src/systemc/ext/tlm_utils/peq_with_cb_and_phase.h @@ -0,0 +1,301 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +// 12-Jan-2009 John Aynsley Bug fix. Phase argument to notify should be const +// 20-Mar-2009 John Aynsley Add cancel_all() method + + +#ifndef __PEQ_WITH_CB_AND_PHASE_H__ +#define __PEQ_WITH_CB_AND_PHASE_H__ + +#ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn +# define SC_INCLUDE_DYNAMIC_PROCESSES +#endif + +#include +#include +#include + +namespace tlm_utils { + +template +class time_ordered_list +{ +public: + struct element + { + struct element *next; + PAYLOAD p; + sc_core::sc_time t; + sc_dt::uint64 d; + element(PAYLOAD& p, sc_core::sc_time t, sc_dt::uint64 d): p(p),t(t),d(d) {} + element(){} + }; + + element *nill; + element *empties; + element *list; + unsigned int size; + + time_ordered_list() + : nill(new element()), + empties(NULL), + list(nill), + size(0) + { + } + + ~time_ordered_list() { + reset(); + while(empties){ + struct element *e=empties->next; + delete empties; + empties=e; + } + delete nill; + } + + void reset() { + while(size) { + delete_top(); + } + } + + void insert(const PAYLOAD& p, sc_core::sc_time t) { + if (!empties) { + empties=new struct element(); + empties->next=NULL; + } + + struct element *e=empties; + empties=empties->next; + e->p=p; + e->t=t; + e->d=sc_core::sc_delta_count(); + + struct element * ancestor=nill; + struct element * iterator=list; + while (iterator!=nill && iterator->t<=t){ + ancestor=iterator; + iterator=iterator->next; + } + if (ancestor==nill){ + e->next=list; + list=e; + } + else { + e->next=iterator; + ancestor->next=e; + } + size++; + } + + void delete_top(){ + if (list != nill) { + struct element *e=list; + list=list->next; + e->next=empties; + empties=e; + size--; + } + } + + unsigned int get_size() + { + return size; + } + + PAYLOAD &top() + { + return list->p; + } + sc_core::sc_time top_time() + { + return list->t; + } + + sc_dt::uint64& top_delta() + { + return list->d; + } + + sc_core::sc_time next_time() + { + return list->next->t; + } +}; + +//--------------------------------------------------------------------------- +/** + * An event queue that can contain any number of pending + * notifications. Each notification have an associate payload. + */ +//--------------------------------------------------------------------------- +template +class peq_with_cb_and_phase: + public sc_core::sc_object +{ + + typedef typename TYPES::tlm_payload_type tlm_payload_type; + typedef typename TYPES::tlm_phase_type tlm_phase_type; + typedef std::pair PAYLOAD; + typedef void (OWNER::*cb)(tlm_payload_type&, const tlm_phase_type&); + + class delta_list{ + public: + delta_list(){ + reset(); + entries.resize(100); + } + + inline void insert(const PAYLOAD& p){ + if (size==entries.size()){ + entries.resize(entries.size()*2); + } + entries[size++]=p; + } + + inline PAYLOAD& get(){ + return entries[out++]; + } + + inline bool next(){ + return out entries; + unsigned int out; + }; + +public: + + peq_with_cb_and_phase(OWNER* _owner, cb _cb) + :sc_core::sc_object( sc_core::sc_gen_unique_name( "peq_with_cb_and_phase" ) ) + ,m_owner(_owner) + ,m_cb(_cb) + { + sc_core::sc_spawn_options opts; + opts.spawn_method(); + opts.set_sensitivity(&m_e); + opts.dont_initialize(); + sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this), + sc_core::sc_gen_unique_name("fec"), &opts); + } + + peq_with_cb_and_phase(const char* _name, OWNER* _owner,cb _cb) + : sc_core::sc_object( _name ) + ,m_owner(_owner) + ,m_cb(_cb) + { + sc_core::sc_spawn_options opts; + opts.spawn_method(); + opts.set_sensitivity(&m_e); + opts.dont_initialize(); + sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this), + sc_core::sc_gen_unique_name("fec"), &opts); + } + + ~peq_with_cb_and_phase(){} + + void notify (tlm_payload_type& t, const tlm_phase_type& p, const sc_core::sc_time& when){ + //t.aquire(); + if (when==sc_core::SC_ZERO_TIME) { + if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) //uneven delta cycle so delta delay is for even cylce + m_even_delta.insert(PAYLOAD(&t,p)); + else + m_uneven_delta.insert(PAYLOAD(&t,p)); //even delta cycle so delta delay is for uneven delta + m_e.notify(sc_core::SC_ZERO_TIME); + } + else { + m_ppq.insert(PAYLOAD(&t,p), when + sc_core::sc_time_stamp() ); + m_e.notify(when); // note, this will only over-right the "newest" event. + } + } + + void notify (tlm_payload_type& t, const tlm_phase_type& p){ + m_immediate_yield.insert(PAYLOAD(&t,p)); + m_e.notify(); // immediate notification + } + + // Cancel all events from the event queue + void cancel_all() { + m_ppq.reset(); + m_uneven_delta.reset(); + m_even_delta.reset(); + m_immediate_yield.reset(); + m_e.cancel(); + } + +private: + + void fec(){ + //immediate yield notifications + while(m_immediate_yield.next()) {PAYLOAD& tmp=m_immediate_yield.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();} + m_immediate_yield.reset(); + + //delta notifications + if (sc_core::sc_delta_count() & (sc_dt::uint64) 0x1) {//uneven delta so put out all payloads for uneven delta + while (m_uneven_delta.next()) {PAYLOAD& tmp=m_uneven_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();} + m_uneven_delta.reset(); + if (m_even_delta.size) m_e.notify(sc_core::SC_ZERO_TIME); + } + else { + while (m_even_delta.next()) {PAYLOAD& tmp=m_even_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();} + m_even_delta.reset(); + if (m_uneven_delta.size) m_e.notify(sc_core::SC_ZERO_TIME); + } + if (!m_ppq.get_size()) return; //there were only delta notification + + //timed notifications + const sc_core::sc_time now=sc_core::sc_time_stamp(); + sc_core::sc_time top=m_ppq.top_time(); + + while(m_ppq.get_size() && top==now) { // push all active ones into target + PAYLOAD& tmp=m_ppq.top(); + (m_owner->*m_cb)(*tmp.first, tmp.second); //tmp.first->release();} + m_ppq.delete_top(); + top=m_ppq.top_time(); + } + if ( m_ppq.get_size()) { + m_e.notify( top - now) ; + } + + } + + OWNER* m_owner; + cb m_cb; + + time_ordered_list m_ppq; + delta_list m_uneven_delta; + delta_list m_even_delta; + delta_list m_immediate_yield; + + sc_core::sc_event m_e; // default event +}; + +} + +#endif // __PEQ_WITH_CB_AND_PHASE_H__ -- cgit v1.2.3