Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: SS_Strand.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_Strand_h__ | |
24 | #define __SS_Strand_h__ | |
25 | ||
26 | /*{{{includes*/ | |
27 | #include "BL_BoundedArray.h" | |
28 | #include "BL_BaseEcc.h" | |
29 | #include "BL_Memory.h" | |
30 | #include "SS_Memory.h" | |
31 | #include "SS_Node.h" | |
32 | #include "SS_Model.h" | |
33 | #include "SS_Trap.h" | |
34 | #include "SS_Interrupt.h" | |
35 | #include "SS_Decode.h" | |
36 | #include "SS_InstrCache.h" | |
37 | #include "SS_Io.h" | |
38 | #include "SS_Tte.h" | |
39 | #include "SS_State.h" | |
40 | #include "SS_Signal.h" | |
41 | #include "SS_Message.h" | |
42 | #include "SS_AsiInfoTable.h" | |
43 | #include "SS_AsiMap.h" | |
44 | #include "SS_Registers.h" | |
45 | #include "SS_SnapShot.h" | |
46 | #include "SS_Tracer.h" | |
47 | #include "SS_PidContext.h" | |
48 | ||
49 | namespace Sam { | |
50 | #include "vcpu.h" | |
51 | } | |
52 | /*}}}*/ | |
53 | ||
54 | class SS_Tlb; | |
55 | ||
56 | extern "C" | |
57 | { | |
58 | typedef SS_Vaddr (*SS_InstMmu)( SS_Vaddr, SS_Vaddr, SS_Strand*, SS_Instr*, SS_InstrCache::Tag* ); | |
59 | typedef SS_Vaddr (*SS_TrapFun)( SS_Vaddr, SS_Vaddr, SS_Strand*, SS_Instr*, SS_Trap::Type ); | |
60 | typedef SS_Vaddr (*SS_MmuTrap)( SS_Vaddr, SS_Vaddr, SS_Strand*, SS_Instr*, SS_Vaddr, SS_Trap::Type ); | |
61 | typedef SS_Vaddr (*SS_DataMmu)( SS_Vaddr, SS_Vaddr, SS_Strand*, SS_Instr*, SS_Vaddr, uint_t mem ); | |
62 | typedef SS_Vaddr (*SS_InvalidAsi)( SS_Vaddr, SS_Vaddr, SS_Strand*, SS_Instr*, SS_Vaddr ); | |
63 | ||
64 | SS_Vaddr ss_break_inst_va_dec( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i ); | |
65 | ||
66 | SS_Vaddr mem_run_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte ); | |
67 | SS_Vaddr io_run_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte ); | |
68 | SS_Vaddr mem_trc_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte ); | |
69 | SS_Vaddr io_trc_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte ); | |
70 | } | |
71 | ||
72 | // ================================================================================== | |
73 | // The SS_Strand class has no virtual methods and classes derived from SS_Strand | |
74 | // can not have virtual methods either. Function pointers are used instead of virtual. | |
75 | // The reason for non-virtual is avoidance of hidden speed penalties and avoiding | |
76 | // an add on computing IRF register offsets: g0 is at offset 0 so we can check for | |
77 | // g0 by comparing index against 0 (this saves setting a constant to compare against). | |
78 | // | |
79 | // Additionally the class has a very open public interface. This does not mean that | |
80 | // all members can be accessed at will. Contrary, all intertfaces (SAM virtual cpu), | |
81 | // verification PLI, PFE are expected to only use methods defined between the Public | |
82 | // Interface Start and End markers below. | |
83 | // ================================================================================== | |
84 | ||
85 | class SS_Strand | |
86 | { | |
87 | public: | |
88 | SS_Strand( SS_Node& _parent, const char* _name, | |
89 | SS_Execute run_exe_table[], | |
90 | SS_Memop mem_run_table_init[][4], | |
91 | SS_Memop mem_trc_table_init[][4], | |
92 | SS_MemErrDetector& mem_err_detector); | |
93 | ~SS_Strand(); | |
94 | ||
95 | void hard_reset(); | |
96 | void warm_reset(bool intp=true); | |
97 | void xtrn_reset(); | |
98 | ||
99 | // run_step() and trc_step() execute count instruction in run (fast) | |
100 | // and trc (slow) mode respectively. Both routines do not check tick | |
101 | // and stick against tick_cmpr, stick_cmpr and the hstick_cmpr. This | |
102 | // is handled separately by run_tick(). The correct order of calling | |
103 | // is run_step() or trc_step() followed by run_tick(). | |
104 | ||
105 | uint64_t run_step( uint64_t count ); | |
106 | uint64_t trc_step( uint64_t count ); | |
107 | ||
108 | void run_tick( uint64_t incr ); | |
109 | ||
110 | void add_tracer( SS_Tracer* t ); | |
111 | void del_tracer( SS_Tracer* t ); | |
112 | ||
113 | void snapshot( SS_SnapShot& ss ); | |
114 | ||
115 | const char* get_node_name() { return name; } | |
116 | ||
117 | void get_name( char* dst ); | |
118 | ||
119 | SS_BreakPoint::Ident break_on_inst_va( SS_Vaddr va ); | |
120 | SS_BreakPoint::Ident break_on_trap( uint_t tt ); | |
121 | SS_BreakPoint::Ident break_on_red_mode(); | |
122 | ||
123 | SS_BreakPoint::Error break_enable( SS_BreakPoint::Ident id ); | |
124 | SS_BreakPoint::Error break_disable( SS_BreakPoint::Ident id ); | |
125 | SS_BreakPoint::Error break_delete( SS_BreakPoint::Ident id ); | |
126 | ||
127 | void irq_launch( SS_Trap::Type, bool do_time_out=true ); | |
128 | ||
129 | enum Cnv2Pa | |
130 | { | |
131 | VA2PA, | |
132 | VA2PA_CTX, | |
133 | VA2PA_CTX_PID, | |
134 | RA2PA, | |
135 | RA2PA_PID, | |
136 | PA2PA | |
137 | }; | |
138 | ||
139 | SS_Paddr va2pa( SS_Vaddr va ) { SS_Paddr pa; return ((cnv2pa)(this,Sam::Vcpu::TRANSLATE_VA_TO_PA,va,0,0,&pa)) ? 0 : pa; } | |
140 | SS_Paddr va2pa( SS_Vaddr va, uint_t ctx ) { SS_Paddr pa; return ((cnv2pa)(this,Sam::Vcpu::TRANSLATE_VA_TO_PA_CTX,va,ctx,0,&pa)) ? 0 : pa; } | |
141 | SS_Paddr va2pa( SS_Vaddr va, uint_t ctx, uint_t pid ) { SS_Paddr pa; return ((cnv2pa)(this,Sam::Vcpu::TRANSLATE_VA_TO_PA_CTX_PID,va,ctx,pid,&pa)) ? 0 : pa; } | |
142 | ||
143 | SS_Paddr ra2pa( SS_Vaddr ra ) { SS_Paddr pa; return ((cnv2pa)(this,Sam::Vcpu::TRANSLATE_RA_TO_PA,ra,0,0,&pa)) ? 0 : pa; } | |
144 | SS_Paddr ra2pa( SS_Vaddr ra, uint_t pid ) { SS_Paddr pa; return ((cnv2pa)(this,Sam::Vcpu::TRANSLATE_RA_TO_PA_PID,ra,0,pid,&pa)) ? 0 : pa; } | |
145 | ||
146 | enum Limits // These are SunSparc limits, not implementation limits | |
147 | { | |
148 | MAX_WP = 7, // Actual limit is 31, but that has never been used. | |
149 | MAX_TL = 7, | |
150 | MAX_GL = 7, | |
151 | MAX_PTL = 2, | |
152 | MAX_PGL = 2 | |
153 | }; | |
154 | ||
155 | enum Mode | |
156 | { | |
157 | SS_USER, | |
158 | SS_PRIV, | |
159 | SS_HPRV | |
160 | }; | |
161 | ||
162 | //====================================================================== | |
163 | // Do not add data members above here and do not change the layout | |
164 | // of the members below here as we need to most critical state | |
165 | // reachable with a single ld/st with immediate offset (4 Kb space). | |
166 | // For that reason the SS_ ctr registers are sorted in 64, 32, 16 & 8 | |
167 | // bit sizes so that there are no unused gaps between the members | |
168 | //====================================================================== | |
169 | ||
170 | // These accessors take a byte offset into the register file, not an index | |
171 | uint64_t& get_irf( int64_t ofs ) { return *(uint64_t*)((char*)this + ofs); } | |
172 | uint32_t& get_frf( int64_t ofs ) { return *(uint32_t*)((char*)this + ofs); } | |
173 | uint64_t& get_drf( int64_t ofs ) { return *(uint64_t*)((char*)this + ofs); } | |
174 | ||
175 | static uint64_t reg_off2idx( int64_t ofs ) { return (ofs-offsetof(SS_Strand,irf))/sizeof(uint64_t); } | |
176 | static uint64_t reg_idx2off( int64_t idx ) { return idx*sizeof(uint64_t)+offsetof(SS_Strand,irf); } | |
177 | ||
178 | static uint64_t freg_off2idx( int64_t ofs ) | |
179 | { | |
180 | uint64_t idx = (ofs-offsetof(SS_Strand,drf))/sizeof(uint32_t); | |
181 | #if defined(ARCH_X64) | |
182 | return (idx ^ 1); | |
183 | #else | |
184 | return idx; | |
185 | #endif | |
186 | } | |
187 | static uint64_t freg_idx2off( int64_t idx ) | |
188 | { | |
189 | #if defined(ARCH_X64) | |
190 | idx ^= 1; | |
191 | #endif | |
192 | return idx*sizeof(uint32_t)+offsetof(SS_Strand,drf); | |
193 | } | |
194 | ||
195 | // set_fprs() sets the dl and du bits based on the ofs (rd). The ofs is | |
196 | // from the this pointer to the frf member + rd index (scaled by 4(%f) or 8(%d)). | |
197 | ||
198 | void set_fprs( int64_t ofs ) { fprs = fprs() | ((ofs - (32 * 4)) >> 7); } | |
199 | ||
200 | uint64_t irf[32]; // %g, %o, %l, %i | |
201 | ||
202 | // Floating point register file. Note that single precision registers | |
203 | // are not listed here since they are aliased with double precision. | |
204 | // The little endian platform such as AMD64 makes this aliasing a little | |
205 | // more tricky. | |
206 | uint64_t drf[32]; // %d | |
207 | ||
208 | // Some processors generate helper sequences of Sparc lookalike | |
209 | // opcodes that use temporary registers. The %g, %i, %l, %o regs | |
210 | // need to be present at the same time as the %t (temps) | |
211 | ||
212 | uint64_t trf[8]; // Temporary registers | |
213 | ||
214 | SS_Pc pc; | |
215 | SS_Npc npc; | |
216 | SS_Gsr gsr; | |
217 | SS_Tick tick; | |
218 | SS_Stick stick; | |
219 | SS_TickCmpr tick_cmpr; | |
220 | SS_StickCmpr stick_cmpr; | |
221 | SS_HstickCmpr hstick_cmpr; | |
222 | SS_Softint softint; | |
223 | SS_Tpc tpc; | |
224 | SS_Tnpc tnpc; | |
225 | SS_Tstate tstate; | |
226 | SS_Tba tba; | |
227 | SS_Htba htba; | |
228 | SS_RstvAddr rstv_addr; // Strand's PowerOnReset vector address | |
229 | SS_Hver hver; | |
230 | SS_Y y; | |
231 | SS_Pstate pstate; | |
232 | SS_Tt tt; | |
233 | SS_Hpstate hpstate; | |
234 | SS_Htstate htstate; | |
235 | SS_SimState sim_state; | |
236 | SS_Ccr ccr; | |
237 | SS_AsiReg asi; | |
238 | SS_Fprs fprs; | |
239 | SS_Tl tl; | |
240 | SS_Gl gl; | |
241 | SS_Cwp cwp; | |
242 | SS_Cansave cansave; | |
243 | SS_Canrestore canrestore; | |
244 | SS_Cleanwin cleanwin; | |
245 | SS_Otherwin otherwin; | |
246 | SS_Wstate wstate; | |
247 | SS_Pil pil; | |
248 | SS_Hintp hintp; | |
249 | SS_StrandId strand_id; // The one and only strand id | |
250 | SS_MaxWp max_wp; // Strand's NWINDOWS - 1 | |
251 | SS_MaxGl max_gl; // Strand's MAX_GL | |
252 | SS_MaxTl max_tl; // Strand's MAX_TL | |
253 | SS_MaxPgl max_pgl; // Strand's MAX_PGL | |
254 | SS_MaxPtl max_ptl; // Strand's MAX_PTL | |
255 | SS_VaBits va_bits; // Size of the SS_Vaddr in bits | |
256 | SS_PaBits pa_bits; // Size of the SS_Paddr in bits | |
257 | SS_LsuCtr lsu_ctr; // ToDo remove this as not all product have this .. | |
258 | SS_InstCount inst_count; // Number of instructions executed so far | |
259 | ||
260 | SS_Fsr fsr; // The real FSR of the simulated host. | |
261 | SS_Fsr fsr_run; // The FSR of the simulated host, excluding tem=0, aexc=0, cexc=0 | |
262 | SS_Fsr fsr_tem; // The FSR.tem bits of the simulated host | |
263 | SS_Fsr fsr_exc; // The FSR.cexc and FSR.aexc of the simulated host | |
264 | uint64_t fsr_cpu; // The FSR of the host (save place for keeping fsr during fpop execution) | |
265 | uint64_t fsr_tmp; // The FSR after an fpop has executed (scratch) | |
266 | ||
267 | bool running; // True when the strand is running | |
268 | bool halted; // True when the strand is halted | |
269 | ||
270 | // unhalt() is called to pull the strand out of halted mode. | |
271 | // The new running mode is _running | |
272 | void unhalt( bool _running=true ) | |
273 | { | |
274 | sim_state.running(_running); | |
275 | if (change_running) | |
276 | (change_running)(this); | |
277 | running = _running; | |
278 | halted = false; | |
279 | } | |
280 | ||
281 | ||
282 | SS_DecodeTable* dec_table; // Pointer to the decode tree | |
283 | SS_Execute* exe_table; // Pointers to tables of execute functions | |
284 | SS_Execute* run_exe_table_ref; // Ref to trace run table | |
285 | SS_Memop (*mem_table)[4]; // Pointers to tables of current memory access functions | |
286 | SS_Memop (*mem_run_table_ref)[4]; // Pointers to tables of fast memory access functions | |
287 | SS_Memop (*mem_trc_table_ref)[4]; // Pointers to tables of tracing memory access functions | |
288 | BL_Memory* memory; // Pointer to RAM | |
289 | SS_Io* io; // Pointer to I/O | |
290 | uint64_t mmu_scratch; // The MMU uses this as scratch space for enidan conversion | |
291 | uint64_t mem_data[8]; // For holding values loaded/stored to memory (avoid %sp adjustment code!) | |
292 | uint8_t stpartial16[16]; // Partial store 16 to partial store 8 byte mask conversion table | |
293 | uint8_t stpartial32[4]; // Partial store 32 to partial store 8 byte mask conversion table | |
294 | uint64_t mem_mask; // Mask used for partial stores ... iso %o6 | |
295 | ||
296 | BL_BoundedArray<BL_EccBits,32> irf_ecc; // Ecc values for IRF RAS | |
297 | SS_MemErrDetector& mem_err_detector; // RAS memory hierarchy error detector | |
298 | ||
299 | // Returns all the I$ information for a paddr associated w/ this core | |
300 | char* icache_info(SS_Paddr pa) | |
301 | { | |
302 | return mem_err_detector.icache_info(pa, this); | |
303 | } | |
304 | ||
305 | // Returns all the I$ information for a set associated w/ this core | |
306 | char* icache_set(uint_t set) | |
307 | { | |
308 | return mem_err_detector.icache_set(set, this); | |
309 | } | |
310 | ||
311 | // Returns all the D$ information for a set associated w/ this core | |
312 | char* dcache_set(uint_t set) | |
313 | { | |
314 | return mem_err_detector.dcache_set(set, this); | |
315 | } | |
316 | ||
317 | // Returns all the L2$ information for a set associated w/ this core | |
318 | char* l2cache_set(uint_t set) | |
319 | { | |
320 | return mem_err_detector.l2cache_set(set, this); | |
321 | } | |
322 | ||
323 | // Returns all the L2$ information for a set associated w/ this core | |
324 | char* l2cache_set(uint_t bank, uint_t set) | |
325 | { | |
326 | return mem_err_detector.l2cache_set(bank, set, this); | |
327 | } | |
328 | ||
329 | protected: | |
330 | union InstBreakpoint | |
331 | { | |
332 | uint32_t md[2]; // Instruction breakpoint opcode match mask and match data | |
333 | uint64_t mask_data; // A union so that a core can update a strand atomically without locks | |
334 | }; | |
335 | ||
336 | BL_BoundedArray<InstBreakpoint,2> inst_iw; | |
337 | SS_Vaddr inst_wp_va_mask; // The bits that should be match for a watchpoint hit. | |
338 | SS_Vaddr inst_wp_va_addr; // Bit0 of addr is used to disable (1) or enable(0) watchpoint. | |
339 | ||
340 | public: | |
341 | // inst_breakpoint_set() sets the mask and data value for instruction | |
342 | // word breakpoints atomically. | |
343 | ||
344 | void inst_breakpoint_set( uint_t index, uint32_t mask, uint32_t data ) | |
345 | { | |
346 | assert((data &~ mask) == 0); // Expect data bits not used in match to be zero'd | |
347 | InstBreakpoint ib; | |
348 | ib.md[0] = mask; | |
349 | ib.md[1] = data; | |
350 | inst_iw[index].mask_data = ib.mask_data; | |
351 | } | |
352 | ||
353 | // inst_breakpoint_hit() returns true when one of the instruction | |
354 | // breakpoints matches. | |
355 | ||
356 | bool inst_breakpoint_hit( uint32_t opc ) | |
357 | { | |
358 | return sim_state.ib_enabled() | |
359 | && (inst_iw[0].md[0] && ((opc & inst_iw[0].md[0]) == inst_iw[0].md[1])) | |
360 | || (inst_iw[1].md[0] && ((opc & inst_iw[1].md[0]) == inst_iw[1].md[1])); | |
361 | } | |
362 | ||
363 | // inst_watchpoint_va_set() sets the instr_watchpoint of virtual | |
364 | // addesses atomically. Note that bit 0 of the inst_wp_va_addr | |
365 | // is used as enabled(bit0=0) and disable (bit0=1) | |
366 | ||
367 | void inst_watchpoint_va_set( SS_Vaddr mask, SS_Vaddr addr ) | |
368 | { | |
369 | inst_wp_va_addr = 1; // Force mismatch always | |
370 | inst_wp_va_mask = mask; | |
371 | inst_wp_va_addr = addr; | |
372 | } | |
373 | SS_Vaddr inst_watchpoint_va_get() | |
374 | { | |
375 | return inst_wp_va_addr; | |
376 | } | |
377 | ||
378 | // inst_watchpoint_va_hit() returns true when the va matches the | |
379 | // set va watchpoints. | |
380 | ||
381 | bool inst_watchpoint_va_hit( SS_Vaddr va ) | |
382 | { | |
383 | return (va & inst_wp_va_mask) == inst_wp_va_addr; | |
384 | } | |
385 | // inst_watchpoint_va_near_hit() returns true when the va matches the | |
386 | // set va watchpoints when the mask is applied first. This is used in | |
387 | // decode cache situations to avoid caching cases that should go through | |
388 | // the mmu to check for va watchpoint hits. | |
389 | ||
390 | bool inst_watchpoint_va_near_hit( SS_Vaddr mask, SS_Vaddr va ) | |
391 | { | |
392 | return (va & inst_wp_va_mask & mask) == (inst_wp_va_addr & (mask + 1)); | |
393 | } | |
394 | ||
395 | // The inst_mmu can set the inst_dec to a decoder that is used just for a | |
396 | // single cache line. The fetch 512 routines resets the inst_dec back to | |
397 | // the save_dec. ss_trap() also resets the inst_dec back to save_dec. | |
398 | // inst_dec and save_dec can cange when breakpoints on instruction opcode | |
399 | // are activated, either for front end use or for hardware purposes. | |
400 | ||
401 | SS_Execute inst_dec; // Pointer to the instruction decode function | |
402 | SS_Execute save_dec; // Always points at the true instruction decoder | |
403 | ||
404 | SS_Tte* fail_tte; // Default tte that always mismatches | |
405 | SS_Tte* inst_tte; // Current tte used by IMMU | |
406 | SS_Tte* trc_inst_tte; // Same as inst_tte for tracing purpose | |
407 | SS_Tte* phys_tte_mem; // The TTE used for MMU bypass, e.g. pa == pa, mode for RAM | |
408 | SS_Tte* phys_tte_io; // The TTE used for MMU bypass, e.g. pa == pa, mode for I/O | |
409 | SS_Tte* phys_tte_mem_am; // The TTE used for MMU bypass, e.g. pa == pa, mode for RAM in V8!?! | |
410 | uint64_t mask_pstate_am; // V8 addressing mode mask | |
411 | ||
412 | SS_AsiReg inst_dft_asi; // Default instruction ASI with priv mode | |
413 | SS_AsiReg data_dft_asi; // Default data ASI with priv mode | |
414 | ||
415 | SS_Tlb* inst_tlb; | |
416 | SS_Tlb* data_tlb; | |
417 | ||
418 | SS_PidContext inst_ctx; // Keep track of partition id and context switching | |
419 | SS_PidContext inst_ctx_pa; // For pa2pa pid and ctx don't care | |
420 | SS_PidContext inst_ctx_ra; // For ra2pa ctx don't care | |
421 | SS_PidContext inst_ctx_va; // For va2pa we do care about pid and ctx | |
422 | SS_PidContext data_ctx; // Keep track of partition id and context switching | |
423 | ||
424 | SS_Chain* inst_tte_link; // Inst TLB tte usage places | |
425 | uint_t inst_tte_link_size; // Inst TLB tte usage places size | |
426 | SS_Chain phys_tte_link; // Phys tte usage places (inst only) | |
427 | SS_Chain* data_tte_link; // Data TLB tte usage places | |
428 | uint_t data_tte_link_size; // Data TLB tte usage places size | |
429 | ||
430 | void (*sim_update)( SS_Strand* ); | |
431 | ||
432 | SS_TrapFun trap; | |
433 | SS_InstMmu inst_mmu; | |
434 | SS_InstMmu inst_mmu_va; | |
435 | SS_InstMmu inst_mmu_ra; | |
436 | SS_InstMmu inst_mmu_pa; | |
437 | SS_DataMmu data_mmu; | |
438 | SS_MmuTrap inst_trap; | |
439 | SS_MmuTrap data_trap; | |
440 | SS_InvalidAsi invalid_asi; | |
441 | ||
442 | const char* (*get_state_name)( SS_Strand*, SS_Registers::Index index ); | |
443 | SS_Registers::Error (*get_state)( SS_Strand*, SS_Registers::Index index, uint64_t* value ); | |
444 | SS_Registers::Error (*set_state)( SS_Strand*, SS_Registers::Index index, uint64_t value ); | |
445 | ||
446 | ||
447 | // The change_running_from_snapshot can be set to signal to | |
448 | // the change_running() routine that it was called after a | |
449 | // restore from a duymp (snapshot). change_running() should | |
450 | // clear the flag when iut sees it set. | |
451 | ||
452 | bool change_running_from_snapshot; | |
453 | void (*change_running)( SS_Strand* ); | |
454 | ||
455 | bool trap_launch_ok( SS_Trap::Type tt ); | |
456 | ||
457 | // In v8plus mode we have assembly routines that call trap. Trap is | |
458 | // implemented in C. So in v8plus mode we have v9 assembly calling a | |
459 | // v8plus piece of code. So we need to make a mode conversion between | |
460 | // the assembly and the c code - note we don't want to recode the assembly. | |
461 | // The same happens for a few other routines. | |
462 | ||
463 | SS_Execute* v8_exe_table; // Pointers to tables of execute functions | |
464 | SS_TrapFun v8_trap; // v9 to v8plus convertor | |
465 | SS_MmuTrap v8_inst_trap; // ,, | |
466 | SS_MmuTrap v8_data_trap; // ,, | |
467 | SS_DataMmu v8_data_mmu; // ,, | |
468 | SS_InvalidAsi v8_invalid_asi; // ,, | |
469 | SS_Execute v8_inst_dec; // Pointer to the instruction decode function in v8 mode | |
470 | ||
471 | // The internal_interrupt and external_interrupt routines deal with | |
472 | // interrupts that come from crosscall or from devices. The external | |
473 | // routine gets a 64 byte payload describing a sun4v interrupt say, | |
474 | // from which it derives and to call the internal routine. The external | |
475 | // routine creates an EXTERNAL_INTERRUPT signal taht is posted with | |
476 | // post_signal; this to make it MP safe. | |
477 | ||
478 | void (*internal_interrupt)( SS_Strand*, uint_t, bool ); | |
479 | void (*external_interrupt)( SS_Strand*, uint64_t*, bool ); | |
480 | ||
481 | // TrapState is one entry on the trap stack. | |
482 | struct TrapState | |
483 | { | |
484 | uint64_t pc; | |
485 | uint64_t npc; | |
486 | uint64_t tstate; | |
487 | uint16_t htstate; | |
488 | uint16_t tt; | |
489 | }; | |
490 | ||
491 | BL_BoundedArray<TrapState,MAX_TL + 1> trap_state; | |
492 | ||
493 | BL_BoundedArray<SS_BreakTrap*,SS_Trap::MAX_TT> break_trap; | |
494 | // Breakpoints on a specific trap | |
495 | SS_BreakRedMode*break_red_mode; // Breakpoints on switch to red mode | |
496 | SS_BreakInstVa* break_inst_va; // Breakpoints on instruction va | |
497 | SS_BreakPoint* break_points; // The current set of breakpoints | |
498 | SS_BreakPoint* break_hit; | |
499 | ||
500 | // skip_break_inst_va is for the case when the pc matches in the inst_mmu | |
501 | // routine rather then in the ss_break_inst_va_dec. In that case we get | |
502 | // double hits ... this boolean is for ignoring the second hit. | |
503 | ||
504 | bool skip_break_inst_va; | |
505 | ||
506 | // test_break_inst_va() returns true when at least one breakpoint | |
507 | // matches the given va. When natching it will insert a break signal | |
508 | // in the strands signal queue that will cause exit of the loop. | |
509 | ||
510 | bool test_break_inst_va( SS_Vaddr va ) | |
511 | { | |
512 | for (SS_BreakInstVa* bp = break_inst_va; bp; bp = (SS_BreakInstVa*)(bp->link)) | |
513 | if (bp->break_inst_va(this,va)) | |
514 | return true; | |
515 | return false; | |
516 | } | |
517 | ||
518 | // near_break_inst_va() returns true when va matches when msk is applied | |
519 | // first ... when the pc walks into a decode cacheline that has a breakpoint | |
520 | // enabled in it. | |
521 | ||
522 | bool near_break_inst_va( SS_Vaddr mask, SS_Vaddr va ) | |
523 | { | |
524 | for (SS_BreakInstVa* bp = break_inst_va; bp; bp = (SS_BreakInstVa*)(bp->link)) | |
525 | if (bp->check_inst_va(mask,va)) | |
526 | return true; | |
527 | return false; | |
528 | } | |
529 | ||
530 | SS_AsiInfoTable asi_info; | |
531 | SS_AsiMap asi_map; | |
532 | SS_InstrCache* inst_cache; | |
533 | SS_Tracer* trc_hook; // Hook for putting different tracers, for trc_step. | |
534 | SS_Strand* run_next; // Pointer to next strand that is in running mode | |
535 | ||
536 | // wrf and grf (and Ecc) point to malloc'ed arrays and never move afterwards | |
537 | ||
538 | uint64_t* wrf; // The window registers | |
539 | BL_EccBits* wrf_ecc; // ECC values for window regs | |
540 | uint64_t* grf; // The global registers | |
541 | BL_EccBits* grf_ecc; // ECC values for global regs | |
542 | ||
543 | BL_BoundedArray<uint64_t,8> scratchpad; // The privileged scratchpad registers | |
544 | BL_BoundedArray<uint64_t,8> hscratchpad; // The hyper privileged scratchpad registers | |
545 | ||
546 | SS_InstrCache* inst_cache_va_nuc_user; // Nucleus context inst cache for user | |
547 | SS_InstrCache* inst_cache_va_pri_user; // Primary context inst cache for user | |
548 | SS_InstrCache* inst_cache_va_nuc_nuc_nuc_priv; // Inst cache for va->pa priv code | |
549 | SS_InstrCache* inst_cache_va_nuc_nuc_sec_priv; // Inst cache for va->pa priv code | |
550 | SS_InstrCache* inst_cache_va_nuc_pri_sec_priv; // Inst cache for va->pa priv code | |
551 | SS_InstrCache* inst_cache_va_pri_priv; // Inst cache for va->pa priv code | |
552 | SS_InstrCache* inst_cache_ra_nuc_user; // Inst cache for user ra->pa code | |
553 | SS_InstrCache* inst_cache_ra_pri_user; // Inst cache for user ra->pa code | |
554 | SS_InstrCache* inst_cache_ra_nuc_priv; // Inst cache for priv ra->pa code | |
555 | SS_InstrCache* inst_cache_ra_pri_priv; // Inst cache for priv ra->pa code | |
556 | SS_InstrCache* inst_cache_pa; // Inst cache for hprv and red mode pa->pa | |
557 | ||
558 | SS_Model* model; | |
559 | SS_Node* parent; | |
560 | const char* name; | |
561 | ||
562 | static void ss_sim_update( SS_Strand* ); | |
563 | static SS_Vaddr ss_trap( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i, SS_Trap::Type tt ); | |
564 | static SS_AsiSpace::Error scratchpad_ld64( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t* ); | |
565 | static SS_AsiSpace::Error scratchpad_st64( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t ); | |
566 | static SS_AsiSpace::Error lsu_ctr_st64 ( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t ); | |
567 | ||
568 | void merge_asi_map(); | |
569 | ||
570 | void cwp_save(); | |
571 | void do_save_inst(); | |
572 | void cwp_load(); | |
573 | void do_restore_inst(); | |
574 | void gl_save(); | |
575 | void gl_load(); | |
576 | void tl_save(); | |
577 | void tl_load(); | |
578 | void get_fsr(); | |
579 | void set_fsr(); | |
580 | void do_retry(); | |
581 | void trc_state(); | |
582 | ||
583 | // irq is the structure that holds all the disrupting traps until they are take. | |
584 | SS_Interrupt irq; | |
585 | ||
586 | // flush_va() is for va watchpoint and va breakpoint detection | |
587 | void flush_va( SS_Vaddr ); | |
588 | ||
589 | // flush() is mainly useful for frontends to flush a particular pa | |
590 | // when code has been written to memory throu the FPE | |
591 | ||
592 | static const uint64_t RAS_TTE_POISON = 1; | |
593 | void flush( SS_Paddr, bool for_ras=false ); | |
594 | ||
595 | void setup_tte_link_tables(); | |
596 | void flush_tte( SS_Tlb* tlb, SS_Tte* ); | |
597 | void flush_tte_all(); | |
598 | ||
599 | SS_Message msg; | |
600 | ||
601 | void post_signal( SS_Signal* sgn ) { msg.post_signal(sgn); } | |
602 | bool peek_signal(); | |
603 | ||
604 | // The swig interface is a bit anoying for the get/set_state methods. | |
605 | // So we provide SWIG (Python) two members to hold errors returned. | |
606 | // This is a workaround, need to look into this to fix (see SWIG pointer.i file) | |
607 | ||
608 | SS_Registers::Error reg_error; | |
609 | SS_AsiSpace::Error asi_error; | |
610 | ||
611 | // cnv2pa is for frontend purposes and translates a given va/ra with optional | |
612 | // given context and optional given partition id to a physical address. | |
613 | // The default context is primary_context[0] . | |
614 | ||
615 | Sam::Vcpu::TranslateError (*cnv2pa)( SS_Strand*, Sam::Vcpu::TranslateMode, SS_Vaddr, uint64_t ctx, uint64_t pid, SS_Paddr* pa ); | |
616 | ||
617 | // Hooks for IRF/FRF ras support | |
618 | SS_RasIrfSrc ras_rs1; // IRF | |
619 | SS_RasIrfSrc ras_rs2; | |
620 | SS_RasIrfSrc ras_rs3; | |
621 | SS_RasIrfDst ras_rd; | |
622 | ||
623 | SS_RasFrfSrc ras_frs1; // Single precison FP | |
624 | SS_RasFrfSrc ras_frs2; | |
625 | SS_RasFrfSrc ras_frs3; | |
626 | SS_RasFrfDst ras_frd; | |
627 | ||
628 | SS_RasDrfSrc ras_drs1; // Double precison FP | |
629 | SS_RasDrfSrc ras_drs2; | |
630 | SS_RasDrfSrc ras_drs3; | |
631 | SS_RasDrfDst ras_drd; | |
632 | ||
633 | // The ras_enable routine is used to turn on RAS features | |
634 | ||
635 | void (*ras_enable)( SS_Strand*, char* cmd); | |
636 | ||
637 | static void default_ras_enable( SS_Strand*, char* cmd ); | |
638 | ||
639 | void (*run_perf) ( SS_Strand* s, Sam::Vcpu::perfcntr which, int64_t incr ); | |
640 | ||
641 | //============================================================================ | |
642 | // For cosim mode we need a few hooks for irq, tlb and other syncing that goes | |
643 | // on between the reference and device under test. All those hooks go here | |
644 | //============================================================================ | |
645 | ||
646 | std::map<SS_Registers::Index,uint64_t> *ctr_sync; | |
647 | ||
648 | void* irq_sync; | |
649 | void (*irq_store)( void* irq_sync, SS_Trap::Type irq_type, bool do_time_out ); | |
650 | ||
651 | void* tlb_sync; | |
652 | void (*inst_tlb_read)( void* tlb_sync ); | |
653 | void inst_tlb_set( SS_Tlb* ); | |
654 | int (*inst_tlb_write)( void* tlb_sync ); | |
655 | void (*inst_tlb_lookup)( void* tlb_sync ); | |
656 | void (*data_tlb_read)( void* tlb_sync ); | |
657 | bool data_tlb_read_skip; | |
658 | int (*data_tlb_write)( void* tlb_sync ); | |
659 | void (*data_tlb_lookup)( void* tlb_sync ); | |
660 | ||
661 | SS_Trap::Type (*inst_hwtw)( SS_Strand* strand, SS_Vaddr va, int_t entry ); | |
662 | SS_Trap::Type (*data_hwtw)( SS_Strand* strand, SS_Vaddr va, uint8_t asi, int_t entry ); | |
663 | ||
664 | bool inst_mmu_error; // Used in cosim to sync trap 0x71 | |
665 | bool data_mmu_error; // Used in cosim to sync trap 0x72 | |
666 | ||
667 | void *asi_ext_obj; // The object that have the external call back function | |
668 | ||
669 | SS_AsiSpace::Error (*asi_ext_ld64_fp)( SS_Node*, void*, SS_Strand* s, SS_Vaddr va, uint64_t* data ); | |
670 | SS_AsiSpace::Error (*asi_ext_st64_fp)( SS_Node*, void*, SS_Strand* s, SS_Vaddr va, uint64_t data ); | |
671 | ||
672 | static SS_AsiSpace::Error asi_ext_ld64( SS_Node* a, void* b, SS_Strand* s, SS_Vaddr va, uint64_t* data ); | |
673 | static SS_AsiSpace::Error asi_ext_st64( SS_Node* a, void* b, SS_Strand* s, SS_Vaddr va, uint64_t data ); | |
674 | ||
675 | static void SS_Strand::ss_run_perf( SS_Strand* s, Sam::Vcpu::perfcntr which, int64_t incr ); | |
676 | ||
677 | static const char* ss_get_state_name( SS_Strand*, SS_Registers::Index index ); | |
678 | static SS_Registers::Error ss_get_state( SS_Strand*, SS_Registers::Index index, uint64_t* value ); | |
679 | static SS_Registers::Error ss_set_state( SS_Strand*, SS_Registers::Index index, uint64_t value ); | |
680 | }; | |
681 | ||
682 | inline void SS_Strand::cwp_save()/*{{{*/ | |
683 | { | |
684 | int i; | |
685 | uint64_t* q = &wrf[cwp()*16]; | |
686 | ||
687 | if (!sim_state.ras_enabled()) | |
688 | { | |
689 | for (i=0; i < 16; i++) | |
690 | q[i] = irf[i + 16]; | |
691 | ||
692 | if (cwp() == max_wp()) | |
693 | q = &wrf[0]; | |
694 | else | |
695 | q = q + 16; | |
696 | ||
697 | for (i=8; i < 16; i++) | |
698 | q[i] = irf[i]; | |
699 | } | |
700 | else | |
701 | { | |
702 | BL_EccBits* q_ecc = &wrf_ecc[cwp()*16]; | |
703 | ||
704 | for (i=0; i < 16; i++) | |
705 | { | |
706 | q[i] = irf[i + 16]; | |
707 | q_ecc[i] = irf_ecc[i + 16]; | |
708 | } | |
709 | ||
710 | if (cwp() == max_wp()) | |
711 | { | |
712 | q = &wrf[0]; | |
713 | q_ecc = &wrf_ecc[0]; | |
714 | } | |
715 | else | |
716 | { | |
717 | q = q + 16; | |
718 | q_ecc += 16; | |
719 | } | |
720 | ||
721 | for (i=8; i < 16; i++) | |
722 | { | |
723 | q[i] = irf[i]; | |
724 | q_ecc[i] = irf_ecc[i]; | |
725 | } | |
726 | } | |
727 | } | |
728 | /*}}}*/ | |
729 | inline void SS_Strand::cwp_load()/*{{{*/ | |
730 | { | |
731 | int i; | |
732 | uint64_t* q = &wrf[cwp()*16]; | |
733 | BL_EccBits* q_ecc = &wrf_ecc[cwp()*16]; | |
734 | ||
735 | if (!sim_state.ras_enabled()) | |
736 | { | |
737 | for (i=0; i < 16; i++) | |
738 | irf[i + 16] = q[i]; | |
739 | ||
740 | if (cwp() == max_wp()) | |
741 | q = &wrf[0]; | |
742 | else | |
743 | q = q + 16; | |
744 | ||
745 | for (i=0; i < 8; i++) | |
746 | irf[i + 8] = q[i + 8]; | |
747 | } | |
748 | else | |
749 | { | |
750 | for (i=0; i < 16; i++) | |
751 | { | |
752 | irf[i + 16] = q[i]; | |
753 | irf_ecc[i + 16] = q_ecc[i]; | |
754 | } | |
755 | ||
756 | if (cwp() == max_wp()) | |
757 | { | |
758 | q = &wrf[0]; | |
759 | q_ecc = &wrf_ecc[0]; | |
760 | } | |
761 | else | |
762 | { | |
763 | q = q + 16; | |
764 | q_ecc += 16; | |
765 | } | |
766 | ||
767 | for (i=0; i < 8; i++) | |
768 | { | |
769 | irf[i + 8] = q[i + 8]; | |
770 | irf_ecc[i + 8] = q_ecc[i + 8]; | |
771 | } | |
772 | } | |
773 | } | |
774 | /*}}}*/ | |
775 | inline void SS_Strand::do_save_inst()/*{{{*/ | |
776 | { | |
777 | int i; | |
778 | uint64_t* q = &wrf[cwp()*16]; | |
779 | ||
780 | if (!sim_state.ras_enabled()) | |
781 | { | |
782 | for (i=0; i < 16; i++) | |
783 | q[i] = irf[i + 16]; | |
784 | ||
785 | for (i=0; i < 8; i++) | |
786 | irf[i + 24] = irf[i + 8]; | |
787 | ||
788 | cwp = (cwp() < max_wp()) ? (cwp() + 1) : 0; | |
789 | cansave = cansave() ? (cansave() - 1) : max_wp(); | |
790 | canrestore = (canrestore() < max_wp()) ? (canrestore() + 1) : 0; | |
791 | q = &wrf[cwp()*16]; | |
792 | ||
793 | for (i=0; i < 8; i++) | |
794 | irf[i + 16] = q[i]; | |
795 | ||
796 | if (cwp() == max_wp()) | |
797 | q = &wrf[0]; | |
798 | else | |
799 | q = q + 16; | |
800 | ||
801 | for (i=0; i < 8; i++) | |
802 | irf[i + 8] = q[i + 8]; | |
803 | } | |
804 | else | |
805 | { | |
806 | BL_EccBits* q_ecc = &wrf_ecc[cwp()*16]; | |
807 | ||
808 | for (i=0; i < 16; i++) | |
809 | { | |
810 | q[i] = irf[i + 16]; | |
811 | q_ecc[i] = irf_ecc[i + 16]; | |
812 | } | |
813 | ||
814 | for (i=0; i < 8; i++) | |
815 | { | |
816 | irf[i + 24] = irf[i + 8]; | |
817 | irf_ecc[i + 24] = irf_ecc[i + 8]; | |
818 | } | |
819 | ||
820 | cwp = (cwp() < max_wp()) ? (cwp() + 1) : 0; | |
821 | cansave = cansave() ? (cansave() - 1) : max_wp(); | |
822 | canrestore = (canrestore() < max_wp()) ? (canrestore() + 1) : 0; | |
823 | q = &wrf[cwp()*16]; | |
824 | q_ecc = &wrf_ecc[cwp()*16]; | |
825 | ||
826 | for (i=0; i < 8; i++) | |
827 | { | |
828 | irf[i + 16] = q[i]; | |
829 | irf_ecc[i + 16] = q_ecc[i]; | |
830 | } | |
831 | ||
832 | if (cwp() == max_wp()) | |
833 | { | |
834 | q = &wrf[0]; | |
835 | q_ecc = &wrf_ecc[0]; | |
836 | } | |
837 | else | |
838 | { | |
839 | q = q + 16; | |
840 | q_ecc += 16; | |
841 | } | |
842 | ||
843 | for (i=0; i < 8; i++) | |
844 | { | |
845 | irf[i + 8] = q[i + 8]; | |
846 | irf_ecc[i + 8] = q_ecc[i + 8]; | |
847 | } | |
848 | } | |
849 | } | |
850 | /*}}}*/ | |
851 | inline void SS_Strand::do_restore_inst()/*{{{*/ | |
852 | { | |
853 | int i; | |
854 | uint64_t* q = &wrf[cwp()*16]; | |
855 | BL_EccBits* q_ecc = &wrf_ecc[cwp()*16]; | |
856 | ||
857 | if (!sim_state.ras_enabled()) | |
858 | { | |
859 | for (i=0; i < 16; i++) | |
860 | q[i] = irf[16 + i]; | |
861 | ||
862 | if (cwp() == max_wp()) | |
863 | q = &wrf[0]; | |
864 | else | |
865 | q = q + 16; | |
866 | ||
867 | for (i=8; i < 16; i++) | |
868 | q[i] = irf[i]; | |
869 | ||
870 | cwp = cwp() ? (cwp() - 1) : max_wp(); | |
871 | cansave = (cansave() < max_wp()) ? (cansave() + 1) : 0; | |
872 | canrestore = canrestore() ? (canrestore() - 1) : max_wp(); | |
873 | ||
874 | q = &wrf[cwp()*16]; | |
875 | ||
876 | for (i=0; i < 8; i++) | |
877 | { | |
878 | irf[i + 8] = irf[i + 24]; | |
879 | irf[i + 24] = q[i + 8]; | |
880 | irf[i + 16] = q[i]; | |
881 | } | |
882 | } | |
883 | else | |
884 | { | |
885 | for (i=0; i < 16; i++) | |
886 | { | |
887 | q[i] = irf[16 + i]; | |
888 | q_ecc[i] = irf_ecc[16 + i]; | |
889 | } | |
890 | ||
891 | if (cwp() == max_wp()) | |
892 | { | |
893 | q = &wrf[0]; | |
894 | q_ecc = &wrf_ecc[0]; | |
895 | } | |
896 | else | |
897 | { | |
898 | q = q + 16; | |
899 | q_ecc = q_ecc + 16; | |
900 | } | |
901 | ||
902 | for (i=8; i < 16; i++) | |
903 | { | |
904 | q[i] = irf[i]; | |
905 | q_ecc[i] = irf_ecc[i]; | |
906 | } | |
907 | ||
908 | cwp = cwp() ? (cwp() - 1) : max_wp(); | |
909 | cansave = (cansave() < max_wp()) ? (cansave() + 1) : 0; | |
910 | canrestore = canrestore() ? (canrestore() - 1) : max_wp(); | |
911 | ||
912 | q = &wrf[cwp()*16]; | |
913 | q_ecc = &wrf_ecc[cwp()*16]; | |
914 | ||
915 | for (i=0; i < 8; i++) | |
916 | { | |
917 | irf[i + 8] = irf[i + 24]; | |
918 | irf[i + 24] = q[i + 8]; | |
919 | irf[i + 16] = q[i]; | |
920 | ||
921 | irf_ecc[i + 8] = irf_ecc[i + 24]; | |
922 | irf_ecc[i + 24] = q_ecc[i + 8]; | |
923 | irf_ecc[i + 16] = q_ecc[i]; | |
924 | } | |
925 | } | |
926 | } | |
927 | /*}}}*/ | |
928 | inline void SS_Strand::gl_save()/*{{{*/ | |
929 | { | |
930 | int i; | |
931 | uint64_t* q = &grf[gl() * 8]; | |
932 | ||
933 | for (i=0; i < 8; i++) | |
934 | q[i] = irf[i]; | |
935 | ||
936 | if (sim_state.ras_enabled()) | |
937 | { | |
938 | BL_EccBits* q_ecc = &grf_ecc[gl() * 8]; | |
939 | ||
940 | for (i=0; i < 8; i++) | |
941 | q_ecc[i] = irf_ecc[i]; | |
942 | } | |
943 | } | |
944 | /*}}}*/ | |
945 | inline void SS_Strand::gl_load()/*{{{*/ | |
946 | { | |
947 | int i; | |
948 | uint64_t* q = &grf[gl() * 8]; | |
949 | ||
950 | for (i=0; i < 8; i++) | |
951 | irf[i] = q[i]; | |
952 | ||
953 | if (sim_state.ras_enabled()) | |
954 | { | |
955 | BL_EccBits* q_ecc = &grf_ecc[gl() * 8]; | |
956 | ||
957 | for (i=0; i < 8; i++) | |
958 | irf_ecc[i] = q_ecc[i]; | |
959 | } | |
960 | } | |
961 | /*}}}*/ | |
962 | ||
963 | #endif |