1 /*
2  *  target.h
3  *
4  *  This file is part of NEST.
5  *
6  *  Copyright (C) 2004 The NEST Initiative
7  *
8  *  NEST is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  NEST is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #ifndef TARGET_H
24 #define TARGET_H
25 
26 // C++ includes:
27 #include <cassert>
28 
29 // Includes from nestkernel:
30 #include "nest_types.h"
31 #include "static_assert.h"
32 #include "exceptions.h"
33 
34 namespace nest
35 {
36 // clang-format off
37 /**
38  * This class implements a 64-bit target neuron identifier type. It uniquely identifies
39  * a target neuron on a (remote) machine. Used in TargetTable for the presynaptic part
40  * of the connection infrastructure.
41  *
42  * The bitwise layout of the neuron identifier for the "standard" CMAKE option:
43  *
44  *  +-------- processed flag
45  *  |   +---- synapse-type id (syn_id)
46  *  |   |
47  *  ||----------||--thread--||---------rank----------||----local connection id (lcid)----|
48  *  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000
49  *  |       |  |       |  |       |  |       |  |       |  |       |  |       |  |       |
50  *  63      56 55      48 47      40 39      32 31      24 23      16 15      8  7       0
51  *
52  * The bitwise layout of the neuron identifier for the "hpc" CMAKE option:
53  *
54  *  +-------- processed flag
55  *  |   +---- synapse-type id (syn_id)
56  *  |   |
57  *  ||-----||---thread----||---------rank------------||----local connection id (lcid)----|
58  *  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000  0000 0000
59  *  |       |  |       |  |       |  |       |  |       |  |       |  |       |  |       |
60  *  63      56 55      48 47      40 39      32 31      24 23      16 15      8  7       0
61  *
62  * Other custom layouts can be chosen by providing a list of 5
63  * numbers, representing the bits required for rank, thread, synapse
64  * id, local connection id and processed flag, respectively. The number
65  * of bits needs to sum to 64. The processed flag must always use one
66  * bit.
67  */
68 // clang-format on
69 
70 enum enum_status_target_id
71 {
72   TARGET_ID_PROCESSED,
73   TARGET_ID_UNPROCESSED
74 };
75 
76 class Target
77 {
78 private:
79   uint64_t remote_target_id_;
80 
81   static constexpr uint8_t BITPOS_LCID = 0U;
82   static constexpr uint8_t BITPOS_RANK = NUM_BITS_LCID;
83   static constexpr uint8_t BITPOS_TID = BITPOS_RANK + NUM_BITS_RANK;
84   static constexpr uint8_t BITPOS_SYN_ID = BITPOS_TID + NUM_BITS_TID;
85   static constexpr uint8_t BITPOS_PROCESSED_FLAG = BITPOS_SYN_ID + NUM_BITS_SYN_ID;
86 
87   using bits_for_processed_flag = StaticAssert< NUM_BITS_PROCESSED_FLAG == 1U >::success;
88   using position_of_processed_flag = StaticAssert< BITPOS_PROCESSED_FLAG == 63U >::success;
89 
90   // generate bit-masks used in bit-operations
91   static constexpr uint64_t MASK_LCID = generate_bit_mask( NUM_BITS_LCID, BITPOS_LCID );
92   static constexpr uint64_t MASK_RANK = generate_bit_mask( NUM_BITS_RANK, BITPOS_RANK );
93   static constexpr uint64_t MASK_TID = generate_bit_mask( NUM_BITS_TID, BITPOS_TID );
94   static constexpr uint64_t MASK_SYN_ID = generate_bit_mask( NUM_BITS_SYN_ID, BITPOS_SYN_ID );
95   static constexpr uint64_t MASK_PROCESSED_FLAG = generate_bit_mask( NUM_BITS_PROCESSED_FLAG, BITPOS_PROCESSED_FLAG );
96 
97 public:
98   Target();
99   Target( const Target& target );
100   Target( const thread tid, const thread rank, const synindex syn_id, const index lcid );
101 
102   Target& operator=( const Target& );
103 
104   /**
105    * Set local connection id.
106    */
107   void set_lcid( const index lcid );
108 
109   /**
110    * Return local connection id.
111    */
112   index get_lcid() const;
113 
114   /**
115    * Set rank.
116    */
117   void set_rank( const thread rank );
118 
119   /**
120    * Return rank.
121    */
122   thread get_rank() const;
123 
124   /**
125    * Set thread id.
126    */
127   void set_tid( const thread tid );
128 
129   /**
130    * Return thread id.
131    */
132   thread get_tid() const;
133 
134   /**
135    * Set the synapse-type id.
136    */
137   void set_syn_id( const synindex syn_id );
138 
139   /**
140    * Return synapse-type id.
141    */
142   synindex get_syn_id() const;
143 
144   /**
145    * Set the status of the target identifier: processed or unprocessed.
146    */
147   void set_status( enum_status_target_id status );
148 
149   /**
150    * Get the status of the target identifier: processed or unprocessed.
151    */
152   enum_status_target_id get_status() const;
153 
154   /**
155    * Return the status od the target identifier: processed or unprocessed.
156    */
157   bool is_processed() const;
158 
159   /**
160    * Return offset.
161    */
162   double get_offset() const;
163 };
164 
165 //!< check legal size
166 using success_target_size = StaticAssert< sizeof( Target ) == 8 >::success;
167 
Target()168 inline Target::Target()
169   : remote_target_id_( 0 )
170 {
171 }
172 
Target(const Target & target)173 inline Target::Target( const Target& target )
174   : remote_target_id_( target.remote_target_id_ )
175 {
176   set_status( TARGET_ID_UNPROCESSED ); // initialize
177 }
178 
179 inline Target& Target::operator=( const Target& other )
180 {
181   remote_target_id_ = other.remote_target_id_;
182   set_status( TARGET_ID_UNPROCESSED );
183   return *this;
184 }
185 
Target(const thread tid,const thread rank,const synindex syn_id,const index lcid)186 inline Target::Target( const thread tid, const thread rank, const synindex syn_id, const index lcid )
187   : remote_target_id_( 0 )
188 {
189   assert( tid <= MAX_TID );
190   assert( rank <= MAX_RANK );
191   assert( syn_id <= MAX_SYN_ID );
192   assert( lcid <= MAX_LCID );
193 
194   set_lcid( lcid );
195   set_rank( rank );
196   set_tid( tid );
197   set_syn_id( syn_id );
198   set_status( TARGET_ID_UNPROCESSED ); // initialize
199 }
200 
201 inline void
set_lcid(const index lcid)202 Target::set_lcid( const index lcid )
203 {
204   assert( lcid <= MAX_LCID );
205   remote_target_id_ = ( remote_target_id_ & ( ~MASK_LCID ) ) | ( static_cast< uint64_t >( lcid ) << BITPOS_LCID );
206 }
207 
208 inline index
get_lcid()209 Target::get_lcid() const
210 {
211   return ( ( remote_target_id_ & MASK_LCID ) >> BITPOS_LCID );
212 }
213 
214 inline void
set_rank(const thread rank)215 Target::set_rank( const thread rank )
216 {
217   assert( rank <= MAX_RANK );
218   remote_target_id_ = ( remote_target_id_ & ( ~MASK_RANK ) ) | ( static_cast< uint64_t >( rank ) << BITPOS_RANK );
219 }
220 
221 inline thread
get_rank()222 Target::get_rank() const
223 {
224   return ( ( remote_target_id_ & MASK_RANK ) >> BITPOS_RANK );
225 }
226 
227 inline void
set_tid(const thread tid)228 Target::set_tid( const thread tid )
229 {
230   assert( tid <= MAX_TID );
231   remote_target_id_ = ( remote_target_id_ & ( ~MASK_TID ) ) | ( static_cast< uint64_t >( tid ) << BITPOS_TID );
232 }
233 
234 inline thread
get_tid()235 Target::get_tid() const
236 {
237   return ( ( remote_target_id_ & MASK_TID ) >> BITPOS_TID );
238 }
239 
240 inline void
set_syn_id(const synindex syn_id)241 Target::set_syn_id( const synindex syn_id )
242 {
243   assert( syn_id <= MAX_SYN_ID );
244   remote_target_id_ = ( remote_target_id_ & ( ~MASK_SYN_ID ) ) | ( static_cast< uint64_t >( syn_id ) << BITPOS_SYN_ID );
245 }
246 
247 inline synindex
get_syn_id()248 Target::get_syn_id() const
249 {
250   return ( ( remote_target_id_ & MASK_SYN_ID ) >> BITPOS_SYN_ID );
251 }
252 
253 inline void
set_status(enum_status_target_id set_status_to)254 Target::set_status( enum_status_target_id set_status_to )
255 {
256   switch ( set_status_to )
257   {
258   case TARGET_ID_PROCESSED:
259     remote_target_id_ = remote_target_id_ | MASK_PROCESSED_FLAG; // set single bit
260     break;
261   case TARGET_ID_UNPROCESSED:
262     remote_target_id_ = remote_target_id_ & ~MASK_PROCESSED_FLAG; // clear single bit
263     break;
264   default:
265     throw InternalError( "Invalid remote target id status." );
266   }
267 }
268 
269 inline enum_status_target_id
get_status()270 Target::get_status() const
271 {
272   if ( ( remote_target_id_ & MASK_PROCESSED_FLAG ) >> BITPOS_PROCESSED_FLAG ) // test single bit
273   {
274     return ( TARGET_ID_PROCESSED );
275   }
276   return ( TARGET_ID_UNPROCESSED );
277 }
278 
279 inline bool
is_processed()280 Target::is_processed() const
281 {
282   return ( get_status() == TARGET_ID_PROCESSED );
283 }
284 
285 inline double
get_offset()286 Target::get_offset() const
287 {
288   return 0;
289 }
290 
291 class OffGridTarget : public Target
292 {
293 private:
294   double offset_;
295 
296 public:
297   OffGridTarget();
298   OffGridTarget( const Target& target, const double offset );
299   double get_offset() const;
300 };
301 
OffGridTarget()302 inline OffGridTarget::OffGridTarget()
303   : Target()
304   , offset_( 0 )
305 {
306 }
307 
OffGridTarget(const Target & target,const double offset)308 inline OffGridTarget::OffGridTarget( const Target& target, const double offset )
309   : Target( target )
310   , offset_( offset )
311 {
312 }
313 
314 inline double
get_offset()315 OffGridTarget::get_offset() const
316 {
317   return offset_;
318 }
319 
320 } // namespace nest
321 
322 #endif // TARGET_H
323