Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_Tlb.h
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: SS_Tlb.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#ifndef __SS_Tlb_h__
24#define __SS_Tlb_h__
25
26#include "SS_Tte.h"
27#include "SS_Node.h"
28#include "SS_Strand.h"
29#include "BL_Mutex.h"
30#include "BL_Atomic.h"
31#include <synch.h>
32
33class SS_Tlb
34{
35 public:
36 enum Type
37 {
38 INST_TLB = 0x1,
39 DATA_TLB = 0x2
40 };
41
42 friend Type operator|( Type a, Type b ) { return Type(int(a)|int(b)); }
43
44
45 SS_Tlb( Type type, uint_t _size );
46 SS_Tlb( SS_Tlb& tlb );
47 ~SS_Tlb();
48
49 uint_t tlb_id() { return tlb_ident; }
50
51 // is_xxxx_tlb() returns true when the TLB is of type xxxx
52
53 bool is_inst_tlb() { return tlb_type & INST_TLB; }
54 bool is_data_tlb() { return tlb_type & DATA_TLB; }
55
56 bool is_a_clone() { return !not_a_clone; }
57
58 // clone() can be called to make a copy of the tlb. The method function
59 // is provided by this class or derived classes. clone() is primarily used in
60 // the SS_TlbSync.
61 SS_Tlb* (*clone)( SS_Tlb* );
62
63 // add_strand() is called by a strand to register itself with the TLB to
64 // receive tte flushes for decode cache updates. (strand unparks)
65 void add_strand( SS_Strand* s );
66
67 // rem_strand() is called by a strand to unregister itself with the TLB to
68 // stop receivingtte flushes for decode cache updates. (strand parks)
69 void rem_strand( SS_Strand* s );
70
71 // reuse_tte() is called by the strand after strand->flush_tte is done and
72 // the usage_count count is decremented to zero (the atomic add returns the
73 // previous value of the atomic count). Note in cosim mode with tlb syncing
74 // we should not call this as we keep all tte's ever created.
75 void reuse_tte( SS_Tte* tte )
76 {
77 assert(tte->usage_count);
78
79 if (bl_atomic_add32(&tte->usage_count,-1) == 1)
80 {
81 tte_list_mutex.lock();
82 tte->next = tte_list;
83 tte->valid_bit(false);
84 tte_list = tte;
85 tte_list_mutex.unlock();
86 }
87 }
88
89 // lock_reuse_tte() is used in SS_Strand::trc_step to hold on to the current
90 // tte used for the instruction trace. SS_Strand::trc_step will call reuse_tte
91 // to unlock the TTE. Locking is done by bumping the flosh_pending count by one
92 // which prevents the recycling of the TTE.
93
94 void lock_reuse_tte( SS_Tte* tte )
95 {
96 bl_atomic_add32(&tte->usage_count,1);
97 }
98
99 // size() returns the size of the tlb in number of TTEs
100 uint_t size()
101 {
102 return tlb_size;
103 }
104
105 // get() return the TTE as index.
106 SS_Tte* get( uint_t index )
107 {
108 assert(index < size());
109 return ptr_table[index];
110 }
111
112 // set() inserts tte into the TLb at index: it copies the TTE contents
113 void set( uint_t index, SS_Tte* tte )
114 {
115 assert(index < size());
116 tlb_access.lock();
117 SS_Tte* old_tte = ptr_table[index];
118 assert(old_tte->index == index);
119 SS_Tte* new_tte = alloc_tte(index);
120 *new_tte = *tte;
121 new_tte->index = index;
122 ptr_table[index] = new_tte;
123 flush_tte(0,old_tte);
124 tlb_access.unlock();
125 }
126
127 // flush() is for frontends that play with tte fields we need a way to flush
128 // the modified tte from the decode caches.
129
130 void flush( SS_Tte* tte )
131 {
132 assert(tte);
133 flush_tte(0,tte);
134 }
135
136 int next_valid_index( int i )
137 {
138 if (0 <= i)
139 for (; i < size(); i++)
140 if (ptr_table[i]->valid())
141 return i;
142 return -1;
143 }
144
145 void dump(FILE *fp=stdout);
146
147 // invalidate_tte() is for demap operations to invalidate a TTE.
148 // It replaces the TTE at index i with a new TTE and calls flush_tte()
149 // to evict the TTE from the decode caches.
150
151 void invalidate_tte( SS_Strand* strand, uint i )
152 {
153 SS_Tte* tte = ptr_table[i];
154 assert(tte->index == i);
155 ptr_table[i] = alloc_tte(i);
156 flush_tte(strand,tte);
157 }
158
159 void invalidate_tte( SS_Strand* strand, SS_Tte* tte )
160 {
161 assert(tte == ptr_table[tte->index]);
162 ptr_table[tte->index] = alloc_tte(tte->index);
163 flush_tte(strand,tte);
164 }
165
166 protected:
167 BL_Mutex tlb_access; // The lock used for gaining write access to the TLB
168
169 // tlb_access_lock() and tlb_access_unlock() are used for TLB insert and
170 // demap. The tlb_access_lock bumps the generation count by one after
171 // locking the tlb access mutex. A tlb lookup routine that
172 // does not need the lock and unlock routines can use tlb_access_enter()
173 // and tlb_access_leave() to ensure that at most one TLB insert or remove
174 // happened. If the results of these routines are different then one or
175 // more tlb modifications happened. If they are the same then zero or
176 // maximum one tlb modification is happening.
177 //
178 // When c and C are tlb_access_enter and leave respectively, and m and M
179 // are tlb_access_lock and unlock respectively, then we can have the
180 // following situaltions.
181 //
182 // cCmM ok, generation count equal. all fine.
183 // cmCM oops, generation count different
184 // cmMC oops, generation count different
185 // mcCM fail, generation count equal but mutexed operation ongoing
186 // mcMC oops, generation count different
187 // mMcC ok, generation count equal. all fine.
188 //
189 // The mcCM case is painfull, but at least it allows us to deal
190 // with recycling memory in not to difficult fashion and have mutex
191 // free TLB lookup which is crucial for MP performance (scalability).
192
193 void tlb_access_lock()
194 {
195 tlb_access.lock();
196 ++generation_count;
197 }
198
199 void tlb_access_unlock()
200 {
201 tlb_access.unlock();
202 }
203
204 uint64_t tlb_access_enter()
205 {
206 return generation_count;
207 }
208
209 uint64_t tlb_access_leave()
210 {
211 return generation_count;
212 }
213
214 static uint_t tlb_id_no; // The next tlb_id number, bumped on creation
215
216 uint_t tlb_ident; // The id of this TLB
217 Type tlb_type; // Inst and or data tlb
218 uint_t tlb_size; // The size of the TLB in no TTEs
219 SS_Tte** ptr_table; // The PTR table points to the tte_table entries
220
221 // flush_tte() is called to signal the strands that a tte should be flushed
222 // from the decode cache. usage_count is set to the number of flushes send
223 // out. Each strand decrements usage_count by one. The tte will not be reused
224 // while usage_count >= 0. The last strand to perform an atomic decrement by -1
225 // on the usage_count during reuse_tte will cause the tte to become available again.
226
227 void flush_tte( SS_Strand* caller, SS_Tte* tte )
228 {
229 if (tte->valid_bit())
230 {
231 if (caller && caller->trc_hook)
232 caller->trc_hook->tlb_update(false,this,tte->index,tte);
233
234 bl_atomic_add32(&tte->usage_count,no_strands - 1); // Initial usage_count is 1
235
236 for (Node* strand=strand_list; strand; strand = strand->next)
237 {
238 SS_Signal* sgn;
239 if (caller)
240 sgn = caller->msg.make_signal(SS_Signal::FLUSH_TTE);
241 else
242 sgn = SS_Signal::alloc(SS_Signal::FLUSH_TTE);
243 sgn->tte = tte;
244 sgn->tlb = this;
245 strand->strand->post_signal(sgn);
246 }
247 }
248 else if ((caller && !caller->sim_state.cosim()) || (caller == 0))
249 {
250 tte_list_mutex.lock();
251 tte->next = tte_list;
252 tte_list = tte;
253 tte_list_mutex.unlock();
254 }
255 }
256
257 // alloc_tte() gets a new tte from either the tte_list or mallocs it.
258 // We initialise the usage_count of the TTE to 1 and we set the index
259 // of the TTE to the index of the ptr_table.
260
261 SS_Tte* alloc_tte_block();
262
263 SS_Tte* alloc_tte( uint_t index )
264 {
265 tte_list_mutex.lock();
266 SS_Tte* help = tte_list;
267 if (help == 0)
268 help = alloc_tte_block();
269 else
270 tte_list = help->next;
271 help->index = index;
272 help->usage_count = 1;
273 tte_list_mutex.unlock();
274 return help;
275 }
276
277 private:
278 volatile uint64_t generation_count; // Each modifications of the TLB bumps the count by 1
279
280 static SS_Tlb* ss_clone( SS_Tlb* );
281
282 class Node
283 {
284 public:
285 Node( SS_Strand* s, Node* _next ) : strand(s), next(_next) {}
286
287 SS_Strand* strand;
288 Node* next;
289 };
290
291 bool not_a_clone; // True when the TLB is the original TLB (false when clone()d)
292 Node* strand_list; // Linked list of all strands that share this TLB
293 uint_t no_strands; // No strands in the strands list
294
295 BL_Mutex tte_list_mutex; // Mutex lock for updating tte_list
296 SS_Tte* tte_list; // List of free tte's that can be used for tlb updates.
297};
298
299#endif