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