Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_Message.h
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: SS_Message.h
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23
24#ifndef __SS_Message_h__
25#define __SS_Message_h__
26
27#include "SS_Signal.h"
28#include "BL_Atomic.h"
29#include "SS_SnapShot.h"
30
31// SS_Message is the container class that holds messages for
32// a strand that need to be dealth with on the next step.
33// The class is the crucial element in the run loop of the
34// strand, and part of it's implementation directly impacts
35// performance in a big way. The SS_Strand::get_signal is
36// the only consumer of this class.
37
38class SS_Message
39{
40 public:
41 SS_Message();
42
43 // is_pending() returns true if one or more messages have been
44 // send to the strand. This routines is the key test in the
45 // tight runloop of the strand and should not be changed.
46
47 uint64_t is_pending()
48 {
49 return pending;
50 }
51
52 // set_reenter_loop() is used to send a message to the strand
53 // that special state such as pstate and hpstate of the strand
54 // changed and w\it needs to get out of the loop to update things
55 // like global variables held in registers. Currently only
56 // SS_Strand::ss_sim_update calls this function.
57
58 void set_reenter_loop() { flag.reenterloop = 1; }
59
60 // clr_reenter_loop() is used to notify that the reenter loop
61 // message is handled.
62
63 void clr_reenter_loop() { flag.reenterloop = 0; }
64
65 // set_handle_trap() is used to message othe strand that the
66 // next step should launch the trap handler. Only SS_Interrupt
67 // calls this method as it controls which trap is launched.
68
69 void set_handle_trap( SS_Trap::Type tt )
70 {
71 assert(tt < SS_Trap::TCC_INSTRUCTION);
72 assert(SS_Trap::Type(flag.trap_type) == SS_Trap::RESERVED);
73 flag.trap_type = tt;
74 }
75
76 // clr_handle_trap() is used to notify that the trap has been
77 // handled: the strand is now set to step into the trap code.
78
79 void clr_handle_trap()
80 {
81 flag.trap_type = SS_Trap::RESERVED;
82 }
83
84 // get_handle_trap() is used to find out if a trap is to be
85 // handled. A return value SS_Trap:RESERVED means no trap.
86
87 SS_Trap::Type get_handle_trap()
88 {
89 return SS_Trap::Type(flag.trap_type);
90 }
91
92 // test_signal() returns true while there are SS_Signal type
93 // messages pending. get_signal() is used to consume those
94 // messages.
95
96 bool test_signal() { return head->next != 0; }
97
98 // post_signal() is used to send a SS_Signal based message
99 // to the strand. The routine is MP safe; it uses a mutex for enqueue.
100
101 void post_signal( SS_Signal* node )
102 {
103 node->next = 0;
104 mutex.lock();
105 tail = tail->next = node;
106 mutex.unlock();
107 bl_atomic_add32((int32_t*)&flag.signal,1);
108 }
109
110 // get_signal() is used by the strand to consume a posted SS_Signal
111 // message. This routine can only be used when test_signal() returns
112 // true. Note each strand has one SS_Message instance so there is
113 // only one user of get_signal(), hence dequeue does not have to
114 // use MP safe constructs.
115
116 SS_Signal* get_signal()
117 {
118 // There is always one SS_Signal on an empty queue. On a non empty queue
119 // the SS_Signal after the head is the one we are interested in.
120
121 SS_Signal* temp = head;
122 SS_Signal* help = temp->next;
123 head = help;
124 assert(help);
125 bl_atomic_add32((int32_t*)&flag.signal,-1);
126 temp->next = free_list;
127 temp->type = SS_Signal::FREE;
128 free_list = temp;
129 ++free_count;
130 if (free_count >= free_count_max)
131 {
132 SS_Signal* h = free_list;
133 for (temp = free_list->next;
134 free_count > free_count_max/2;
135 free_list = temp)
136 {
137 assert(free_list->type == SS_Signal::FREE);
138 assert(free_count > 0);
139 --free_count;
140 temp = free_list->next;
141 }
142 SS_Signal* t = free_list;
143 free_list = t->next;
144 assert(free_count > 0);
145 --free_count;
146 SS_Signal::list_free(h, t);
147 }
148
149 return help;
150 }
151
152 // make_signal() creates a new signal that can be posted to a strand.
153 // This class maintains it's own pool of signals for MP scalability
154 // reasons.
155
156 SS_Signal* make_signal( SS_Signal::Type type )
157 {
158 SS_Signal* help = free_list;
159 if (help == 0)
160 {
161 assert(free_count == 0);
162 return SS_Signal::alloc(type);
163 }
164 else
165 {
166 assert(free_count > 0);
167 --free_count;
168 }
169 free_list = help->next;
170 help->init(type);
171 return help;
172 }
173
174 void snapshot( SS_SnapShot& ss, const char* prefix );
175
176 private:
177 BL_Mutex mutex;
178
179 // The Flags structure holds all fast but not MP safe flags. These
180 // can only be set by the strand itself. The signal flag is used
181 // for the MP safe SS_Signal based list.
182
183 struct Flags
184 {
185 uint8_t reenterloop; // Get out of tight loop and reenter
186 uint8_t trap_type; // Handle (disrupting) trap on th next step
187 uint8_t spare[2]; // Reserved for future fast lock free flags
188 int32_t signal; // Used to count number SS_Signals pending
189 };
190
191 union
192 {
193 uint64_t pending; // One 8 byte load to test all the flags
194 Flags flag; // The flags for fast messages
195 };
196
197 // The signal queue always has a valid head and tail pointer.
198
199 SS_Signal* head; // Head of the message queue
200 SS_Signal* tail; // Tail of the message queue
201 SS_Signal* free_list; // Free list of signals
202 uint_t free_count; // Nr signals on free list
203 static const uint_t free_count_max = 1024;
204};
205
206#endif