Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: SS_Strand.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | #include "SS_Strand.h" | |
26 | #include "SS_Tlb.h" | |
27 | #if !defined(ARCH_X64) | |
28 | #include "SS_Prefetch.h" | |
29 | #endif | |
30 | #include "SS_V8Code.h" | |
31 | #include <new> | |
32 | ||
33 | extern "C" SS_Vaddr ss_run_dec( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/ | |
34 | { | |
35 | SS_Decode d = s->dec_table->decode(i->opc); | |
36 | return (d)(pc,npc,s,i,i->opc()); | |
37 | } | |
38 | /*}}}*/ | |
39 | extern "C" SS_Vaddr ss_ibe_dec( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/ | |
40 | { | |
41 | if (s->inst_breakpoint_hit(i->opc())) | |
42 | { | |
43 | return (s->trap)(pc,npc,s,i,SS_Trap::INSTRUCTION_BREAKPOINT); | |
44 | } | |
45 | else | |
46 | { | |
47 | SS_Decode d = s->dec_table->decode(i->opc); | |
48 | return (d)(pc,npc,s,i,i->opc()); | |
49 | } | |
50 | } | |
51 | /*}}}*/ | |
52 | ||
53 | extern "C" SS_Vaddr ss_break_inst_va_dec( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/ | |
54 | { | |
55 | if (s->skip_break_inst_va || !s->test_break_inst_va(pc)) | |
56 | { | |
57 | s->skip_break_inst_va = false; | |
58 | ||
59 | // If the breakpoint did not trigger then decode: ss_run_dec or | |
60 | // ss_ibe_dec ... and execute the instruction. | |
61 | ||
62 | pc = (s->inst_dec)(pc,npc,s,i); | |
63 | ||
64 | // Undo the decode execute caching to make sure resume after | |
65 | // breakpoint hits the breakpoint again. | |
66 | ||
67 | i->exe = ss_break_inst_va_dec; | |
68 | } | |
69 | return pc; | |
70 | } | |
71 | /*}}}*/ | |
72 | ||
73 | class SS_FailTte : public SS_Tte/*{{{*/ | |
74 | { | |
75 | public: | |
76 | SS_FailTte() | |
77 | : | |
78 | SS_Tte() | |
79 | { | |
80 | virt_page = ~0; | |
81 | virt_mask = 0; | |
82 | phys_page = 0; | |
83 | phys_mask = ~0; | |
84 | ||
85 | usage_count = 1; | |
86 | } | |
87 | }; | |
88 | /*}}}*/ | |
89 | class SS_PhysTte : public SS_Tte/*{{{*/ | |
90 | { | |
91 | public: | |
92 | SS_PhysTte() | |
93 | : | |
94 | SS_Tte() | |
95 | { | |
96 | tte_flags = VALID_BIT; // Make sure we can use valid_bit() test on tte | |
97 | virt_page = 0; | |
98 | virt_mask = 0; | |
99 | phys_page = 0; | |
100 | phys_mask = 0; | |
101 | ||
102 | usage_count = 1; | |
103 | } | |
104 | }; | |
105 | /*}}}*/ | |
106 | ||
107 | static SS_FailTte fail_tte; | |
108 | static SS_FailTte junk_tte; | |
109 | ||
110 | // For pa2pa translations we have two areas, memory and i/o. For some | |
111 | // product we use a third one which is only used when pstate.am masking | |
112 | // is applied in pa2pa mode. | |
113 | ||
114 | static SS_PhysTte phys_tte_mem; | |
115 | static SS_PhysTte phys_tte_io; | |
116 | static SS_PhysTte phys_tte_mem_am; | |
117 | ||
118 | static uint8_t ss_stpartial16[] = /*{{{*/ | |
119 | { | |
120 | 0x00, 0x03, 0x0c, 0x0f, | |
121 | 0x30, 0x33, 0x3c, 0x3f, | |
122 | 0xc0, 0xc3, 0xcc, 0xcf, | |
123 | 0xf0, 0xf3, 0xfc, 0xff | |
124 | }; | |
125 | /*}}}*/ | |
126 | static uint8_t ss_stpartial32[] = /*{{{*/ | |
127 | { | |
128 | 0x00, 0x0f, 0xf0, 0xff | |
129 | }; | |
130 | /*}}}*/ | |
131 | ||
132 | SS_Strand::SS_Strand( SS_Node& _parent, const char* _name, /*{{{*/ | |
133 | SS_Execute run_exe_table_init[], | |
134 | SS_Memop mem_run_table_init[][4], | |
135 | SS_Memop mem_trc_table_init[][4], | |
136 | SS_MemErrDetector& _mem_err_detector) | |
137 | : | |
138 | run_exe_table_ref(run_exe_table_init), | |
139 | mem_run_table_ref(mem_run_table_init), | |
140 | mem_trc_table_ref(mem_trc_table_init), | |
141 | mem_err_detector(_mem_err_detector), | |
142 | running(false), | |
143 | dec_table(0), | |
144 | exe_table(0), | |
145 | mem_table(0), | |
146 | #ifndef COMPILE_FOR_SAM | |
147 | memory(&SS_Memory::memory), | |
148 | #endif | |
149 | io(&SS_Io::io), | |
150 | inst_wp_va_mask(0), | |
151 | inst_wp_va_addr(1), // bit0 == 1 is disabled | |
152 | inst_dec(ss_run_dec), | |
153 | save_dec(ss_run_dec), | |
154 | fail_tte(&::fail_tte), | |
155 | inst_tte(&::junk_tte), | |
156 | trc_inst_tte(&::junk_tte), | |
157 | phys_tte_mem(&::phys_tte_mem), | |
158 | phys_tte_io(&::phys_tte_io), | |
159 | phys_tte_mem_am(&::phys_tte_mem_am), | |
160 | inst_dft_asi(), | |
161 | data_dft_asi(), | |
162 | inst_tlb(0), | |
163 | data_tlb(0), | |
164 | inst_tte_link(0), | |
165 | data_tte_link(0), | |
166 | phys_tte_link(), | |
167 | sim_update(ss_sim_update), | |
168 | trap((SS_TrapFun)ss_trap), | |
169 | invalid_asi(0), // ToDo provide default routine | |
170 | get_state(ss_get_state), | |
171 | set_state(ss_set_state), | |
172 | inst_mmu(0), | |
173 | inst_mmu_va(0), | |
174 | inst_mmu_ra(0), | |
175 | inst_mmu_pa(0), | |
176 | inst_trap(0), | |
177 | data_mmu(0), | |
178 | data_trap(0), | |
179 | change_running_from_snapshot(false), | |
180 | change_running(0), | |
181 | break_red_mode(0), | |
182 | break_inst_va(0), | |
183 | break_points(0), | |
184 | break_hit(0), | |
185 | skip_break_inst_va(false), | |
186 | inst_cache(0), | |
187 | trc_hook(0), | |
188 | inst_cache_va_pri_priv(0), | |
189 | inst_cache_va_nuc_nuc_nuc_priv(0), | |
190 | inst_cache_va_nuc_nuc_sec_priv(0), | |
191 | inst_cache_va_nuc_pri_sec_priv(0), | |
192 | inst_cache_va_pri_user(0), | |
193 | inst_cache_va_nuc_user(0), | |
194 | inst_cache_ra_pri_user(0), | |
195 | inst_cache_ra_nuc_user(0), | |
196 | inst_cache_ra_pri_priv(0), | |
197 | inst_cache_ra_nuc_priv(0), | |
198 | inst_cache_pa(0), | |
199 | ras_rs1(0), // Ras Irf hooks | |
200 | ras_rs2(0), | |
201 | ras_rs3(0), | |
202 | ras_rd(0), | |
203 | ras_frs1(0), // Single precison FP RAS hooks | |
204 | ras_frs2(0), | |
205 | ras_frs3(0), | |
206 | ras_frd(0), | |
207 | ras_drs1(0), // Double precison FP RAS hooks | |
208 | ras_drs2(0), | |
209 | ras_drs3(0), | |
210 | ras_drd(0), | |
211 | model(0), // derived strand sets pointer model | |
212 | parent(&_parent), | |
213 | name(strdup(_name)) | |
214 | , irq_sync(0) | |
215 | , irq_store(0) | |
216 | , tlb_sync(0) | |
217 | , inst_tlb_read(0) | |
218 | , inst_tlb_write(0) | |
219 | , inst_tlb_lookup(0) | |
220 | , data_tlb_read(0) | |
221 | , data_tlb_read_skip(false) | |
222 | , data_tlb_write(0) | |
223 | , data_tlb_lookup(0) | |
224 | , inst_hwtw(0) | |
225 | , data_hwtw(0) | |
226 | , inst_mmu_error(false) | |
227 | , data_mmu_error(false) | |
228 | { | |
229 | inst_cache_va_pri_priv = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
230 | inst_cache_va_nuc_nuc_nuc_priv = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
231 | inst_cache_va_nuc_nuc_sec_priv = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
232 | inst_cache_va_nuc_pri_sec_priv = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
233 | inst_cache_va_pri_user = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
234 | inst_cache_va_nuc_user = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
235 | inst_cache_ra_pri_user = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
236 | inst_cache_ra_nuc_user = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
237 | inst_cache_ra_pri_priv = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
238 | inst_cache_ra_nuc_priv = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
239 | inst_cache_pa = (SS_InstrCache*)ss_memalign(1024,sizeof(SS_InstrCache)); | |
240 | ||
241 | inst_cache_va_pri_priv->init ("vpp", &::junk_tte); | |
242 | inst_cache_va_nuc_nuc_nuc_priv->init("vnp-00",&::junk_tte); | |
243 | inst_cache_va_nuc_nuc_sec_priv->init("vnp-0s",&::junk_tte); | |
244 | inst_cache_va_nuc_pri_sec_priv->init("vnp-ps",&::junk_tte); | |
245 | inst_cache_va_pri_user->init ("vpu", &::junk_tte); | |
246 | inst_cache_va_nuc_user->init ("vnu", &::junk_tte); | |
247 | inst_cache_ra_pri_user->init ("rpu", &::junk_tte); | |
248 | inst_cache_ra_nuc_user->init ("rnu", &::junk_tte); | |
249 | inst_cache_ra_pri_priv->init ("rpp", &::junk_tte); | |
250 | inst_cache_ra_nuc_priv->init ("rnp", &::junk_tte); | |
251 | inst_cache_pa->init ("p--", &::junk_tte); | |
252 | ||
253 | wrf = (uint64_t*)ss_memalign(64,sizeof(uint64_t) * (MAX_WP + 1) * 16); | |
254 | wrf_ecc = (BL_EccBits*)ss_malloc( sizeof(BL_EccBits) * (MAX_WP + 1) * 16); | |
255 | grf = (uint64_t*)ss_memalign(64,sizeof(uint64_t) * (MAX_GL + 1) * 8); | |
256 | grf_ecc = (BL_EccBits*)ss_malloc( sizeof(BL_EccBits) * (MAX_GL + 1) * 8); | |
257 | ||
258 | break_trap.memset(0); | |
259 | memset(irf,0,32 * sizeof(uint64_t)); | |
260 | memset(drf,0,32 * sizeof(uint64_t)); | |
261 | trap_state.memset(0); | |
262 | scratchpad.memset(0); | |
263 | hscratchpad.memset(0); | |
264 | memset(wrf,0,(MAX_WP + 1) * 16 * sizeof(uint64_t)); | |
265 | memset(wrf_ecc,0,(MAX_WP + 1) * 16 * sizeof(BL_EccBits)); | |
266 | memset(grf,0,(MAX_GL + 1) * 8 * sizeof(uint64_t)); | |
267 | memset(grf_ecc,0,(MAX_GL + 1) * 8 * sizeof(BL_EccBits)); | |
268 | ||
269 | max_tl = 5; | |
270 | max_gl = 4; | |
271 | max_ptl = 2; | |
272 | max_pgl = 2; | |
273 | max_wp = 7; | |
274 | ||
275 | va_bits = 64; | |
276 | pa_bits = 55; | |
277 | ||
278 | rstv_addr = 0xfffffffff0000000; | |
279 | ||
280 | sim_state = 0; | |
281 | sim_state.fp_disabled(1); | |
282 | sim_state.ib_enabled(0); | |
283 | sim_state.red(1); | |
284 | ||
285 | #ifdef COMPILE_FOR_COSIM | |
286 | sim_state.cosim(1); | |
287 | #endif | |
288 | ||
289 | for (int h=0; h<16; h++) | |
290 | stpartial16[h] = ss_stpartial16[h]; | |
291 | for (int w=0; w<4; w++) | |
292 | stpartial32[w] = ss_stpartial32[w]; | |
293 | ||
294 | inst_iw[0].mask_data = 0; | |
295 | inst_iw[1].mask_data = 0; | |
296 | ||
297 | ras_enable = default_ras_enable; | |
298 | ||
299 | run_perf = ss_run_perf; | |
300 | ||
301 | #if !defined(ARCH_X64) | |
302 | v8_trap = trap_v9_to_v8plus; | |
303 | v8_inst_trap = inst_trap_v9_to_v8plus; | |
304 | v8_data_trap = data_trap_v9_to_v8plus; | |
305 | v8_data_mmu = data_mmu_v9_to_v8plus; | |
306 | v8_invalid_asi = invalid_asi_v9_to_v8plus; | |
307 | v8_inst_dec = inst_dec_v9_to_v8plus; | |
308 | #endif | |
309 | ||
310 | } | |
311 | /*}}}*/ | |
312 | SS_Strand::~SS_Strand()/*{{{*/ | |
313 | { | |
314 | free((char*)name); | |
315 | } | |
316 | /*}}}*/ | |
317 | ||
318 | void SS_Strand::hard_reset()/*{{{*/ | |
319 | { | |
320 | ss_trap(0,0,this,0,SS_Trap::POWER_ON_RESET); | |
321 | } | |
322 | /*}}}*/ | |
323 | void SS_Strand::warm_reset(bool intp)/*{{{*/ | |
324 | { | |
325 | // ToDo we need a better trap type for this and handle the | |
326 | // common warm reset there like hard and xtrn reset | |
327 | if (intp) | |
328 | ss_trap(0,0,this,0,SS_Trap::POWER_ON_RESET); | |
329 | } | |
330 | /*}}}*/ | |
331 | void SS_Strand::xtrn_reset()/*{{{*/ | |
332 | { | |
333 | ss_trap(0,0,this,0,SS_Trap::EXTERNALLY_INITIATED_RESET); | |
334 | } | |
335 | /*}}}*/ | |
336 | ||
337 | const char* SS_Strand::ss_get_state_name( SS_Strand* s, SS_Registers::Index index )/*{{{*/ | |
338 | { | |
339 | if (SS_Registers::is_asr(index)) | |
340 | { | |
341 | switch (index) | |
342 | { | |
343 | case SS_Registers::ASR_Y: return s->y.name(); | |
344 | case SS_Registers::ASR_CCR: return s->ccr.name(); | |
345 | case SS_Registers::ASR_ASI: return "asi"; // Internal name is asi_reg ... | |
346 | case SS_Registers::ASR_TICK: return s->tick.name(); | |
347 | case SS_Registers::ASR_PC: return s->pc.name(); | |
348 | case SS_Registers::ASR_FPRS: return s->fprs.name(); | |
349 | case SS_Registers::ASR_GSR: return s->gsr.name(); | |
350 | case SS_Registers::ASR_SOFTINT_SET: return SS_SoftintSet().name(); | |
351 | case SS_Registers::ASR_SOFTINT_CLR: return SS_SoftintClr().name(); | |
352 | case SS_Registers::ASR_SOFTINT: return s->softint.name(); | |
353 | case SS_Registers::ASR_TICK_CMPR: return s->tick_cmpr.name(); | |
354 | case SS_Registers::ASR_STICK: return s->stick.name(); | |
355 | case SS_Registers::ASR_STICK_CMPR: return s->stick_cmpr.name(); | |
356 | default: break; | |
357 | } | |
358 | } | |
359 | else if (SS_Registers::is_pr(index)) | |
360 | { | |
361 | switch (index) | |
362 | { | |
363 | case SS_Registers::PR_TPC: return s->tpc.name(); | |
364 | case SS_Registers::PR_TNPC: return s->tnpc.name(); | |
365 | case SS_Registers::PR_TSTATE: return s->tstate.name(); | |
366 | case SS_Registers::PR_TT: return s->tt.name(); | |
367 | case SS_Registers::PR_TICK: return "pr_tick"; // Avoid cases with same name | |
368 | case SS_Registers::PR_TBA: return s->tba.name(); | |
369 | case SS_Registers::PR_PSTATE: return s->pstate.name(); | |
370 | case SS_Registers::PR_TL: return s->tl.name(); | |
371 | case SS_Registers::PR_PIL: return s->pil.name(); | |
372 | case SS_Registers::PR_CWP: return s->cwp.name(); | |
373 | case SS_Registers::PR_CANSAVE: return s->cansave.name(); | |
374 | case SS_Registers::PR_CANRESTORE: return s->canrestore.name(); | |
375 | case SS_Registers::PR_CLEANWIN: return s->cleanwin.name(); | |
376 | case SS_Registers::PR_OTHERWIN: return s->otherwin.name(); | |
377 | case SS_Registers::PR_WSTATE: return s->wstate.name(); | |
378 | case SS_Registers::PR_GL: return s->gl.name(); | |
379 | default: break; | |
380 | } | |
381 | } | |
382 | else if (SS_Registers::is_hpr(index)) | |
383 | { | |
384 | switch (index) | |
385 | { | |
386 | case SS_Registers::HPR_HPSTATE: return s->hpstate.name(); | |
387 | case SS_Registers::HPR_HTSTATE: return s->htstate.name(); | |
388 | case SS_Registers::HPR_HINTP: return s->hintp.name(); | |
389 | case SS_Registers::HPR_HTBA: return s->htba.name(); | |
390 | case SS_Registers::HPR_HVER: return s->hver.name(); | |
391 | case SS_Registers::HPR_HSTICK_CMPR: return s->hstick_cmpr.name(); | |
392 | default: break; | |
393 | } | |
394 | } | |
395 | else if (SS_Registers::is_sim(index)) | |
396 | { | |
397 | switch (index) | |
398 | { | |
399 | case SS_Registers::SIM_MAX_WP: return s->max_wp.name(); | |
400 | case SS_Registers::SIM_MAX_TL: return s->max_tl.name(); | |
401 | case SS_Registers::SIM_MAX_PTL: return s->max_ptl.name(); | |
402 | case SS_Registers::SIM_MAX_GL: return s->max_gl.name(); | |
403 | case SS_Registers::SIM_MAX_PGL: return s->max_pgl.name(); | |
404 | case SS_Registers::SIM_RSTV_ADDR: return s->rstv_addr.name(); | |
405 | case SS_Registers::SIM_NPC: return s->npc.name(); | |
406 | case SS_Registers::SIM_FSR: return s->fsr.name(); | |
407 | case SS_Registers::SIM_STATE: return s->sim_state.name(); | |
408 | case SS_Registers::SIM_STRAND_ID: return s->strand_id.name(); | |
409 | case SS_Registers::SIM_PA_BITS: return s->pa_bits.name(); | |
410 | case SS_Registers::SIM_VA_BITS: return s->va_bits.name(); | |
411 | case SS_Registers::SIM_INST_COUNT: return s->inst_count.name(); | |
412 | default: break; | |
413 | } | |
414 | } | |
415 | else if (SS_Registers::is_irf(index)) | |
416 | return SS_Registers::irf_name[index - SS_Registers::IRF_OFS]; | |
417 | else if (SS_Registers::is_drf(index)) | |
418 | return SS_Registers::drf_name[index - SS_Registers::DRF_OFS]; | |
419 | else if (SS_Registers::is_frf(index)) | |
420 | return SS_Registers::frf_name[index - SS_Registers::FRF_OFS]; | |
421 | ||
422 | return 0; | |
423 | } | |
424 | /*}}}*/ | |
425 | SS_Registers::Error SS_Strand::ss_get_state( SS_Strand* s, SS_Registers::Index index, uint64_t* value )/*{{{*/ | |
426 | { | |
427 | if (SS_Registers::is_irf(index)) | |
428 | *value = s->irf[index - SS_Registers::IRF_OFS]; | |
429 | else if (SS_Registers::is_drf(index)) | |
430 | *value = s->drf[index - SS_Registers::DRF_OFS]; | |
431 | else if (SS_Registers::is_frf(index)) | |
432 | *value = s->get_frf(SS_Strand::freg_idx2off(index - SS_Registers::FRF_OFS)); | |
433 | else | |
434 | { | |
435 | // For processors that do not implement the full 64bit for virtual address | |
436 | // we need to make sure that the unimplemented bits are sign extended based | |
437 | // on bit[va_bits() - 1]. This is done for pc, npc, tpc, tnpc | |
438 | ||
439 | uint_t sft = 64 - s->va_bits(); | |
440 | ||
441 | switch (index) | |
442 | { | |
443 | case SS_Registers::ASR_Y: *value = s->y(); break; | |
444 | case SS_Registers::ASR_CCR: *value = s->ccr(); break; | |
445 | case SS_Registers::ASR_ASI: *value = s->asi(); break; | |
446 | case SS_Registers::ASR_TICK: *value = s->tick(); break; | |
447 | case SS_Registers::ASR_PC: *value = int64_t(s->pc() << sft) >> sft; break; | |
448 | case SS_Registers::ASR_FPRS: *value = s->fprs(); break; | |
449 | case SS_Registers::ASR_GSR: *value = s->gsr(); break; | |
450 | case SS_Registers::ASR_SOFTINT: *value = s->softint(); break; | |
451 | case SS_Registers::ASR_SOFTINT_CLR: *value = s->softint(); break; | |
452 | case SS_Registers::ASR_SOFTINT_SET: *value = s->softint(); break; | |
453 | case SS_Registers::ASR_TICK_CMPR: *value = s->tick_cmpr(); break; | |
454 | case SS_Registers::ASR_STICK: *value = s->stick(); break; | |
455 | case SS_Registers::ASR_STICK_CMPR: *value = s->stick_cmpr(); break; | |
456 | case SS_Registers::PR_TICK: *value = s->tick(); break; | |
457 | case SS_Registers::PR_TBA: *value = s->tba(); break; | |
458 | case SS_Registers::PR_PSTATE: *value = s->pstate(); break; | |
459 | case SS_Registers::PR_TL: *value = s->tl(); break; | |
460 | case SS_Registers::PR_PIL: *value = s->pil(); break; | |
461 | case SS_Registers::PR_CWP: *value = s->cwp(); break; | |
462 | case SS_Registers::PR_CANSAVE: *value = s->cansave(); break; | |
463 | case SS_Registers::PR_CANRESTORE: *value = s->canrestore(); break; | |
464 | case SS_Registers::PR_CLEANWIN: *value = s->cleanwin(); break; | |
465 | case SS_Registers::PR_OTHERWIN: *value = s->otherwin(); break; | |
466 | case SS_Registers::PR_WSTATE: *value = s->wstate(); break; | |
467 | case SS_Registers::PR_GL: *value = s->gl(); break; | |
468 | case SS_Registers::HPR_HPSTATE: *value = s->hpstate(); break; | |
469 | case SS_Registers::HPR_HINTP: *value = s->hintp(); break; | |
470 | case SS_Registers::HPR_HTBA: *value = s->htba(); break; | |
471 | case SS_Registers::HPR_HVER: *value = s->hver(); break; | |
472 | case SS_Registers::HPR_HSTICK_CMPR: *value = s->hstick_cmpr(); break; | |
473 | case SS_Registers::SIM_MAX_WP: *value = s->max_wp(); break; | |
474 | case SS_Registers::SIM_MAX_TL: *value = s->max_tl(); break; | |
475 | case SS_Registers::SIM_MAX_PTL: *value = s->max_ptl(); break; | |
476 | case SS_Registers::SIM_MAX_GL: *value = s->max_gl(); break; | |
477 | case SS_Registers::SIM_MAX_PGL: *value = s->max_pgl(); break; | |
478 | case SS_Registers::SIM_RSTV_ADDR: *value = s->rstv_addr(); break; | |
479 | case SS_Registers::SIM_NPC: *value = int64_t(s->npc() << sft) >> sft; break; | |
480 | case SS_Registers::SIM_STATE: *value = s->sim_state(); break; | |
481 | case SS_Registers::SIM_STRAND_ID: *value = s->strand_id(); break; | |
482 | case SS_Registers::SIM_PA_BITS: *value = s->pa_bits(); break; | |
483 | case SS_Registers::SIM_VA_BITS: *value = s->va_bits(); break; | |
484 | case SS_Registers::SIM_INST_COUNT: *value = s->inst_count(); break; | |
485 | ||
486 | case SS_Registers::SIM_FSR: | |
487 | s->get_fsr(); | |
488 | *value = s->fsr(); | |
489 | break; | |
490 | ||
491 | case SS_Registers::PR_TPC: | |
492 | if (s->tl() == 0) | |
493 | return SS_Registers::NOT_AVAILABLE; | |
494 | *value = int64_t(s->tpc() << sft) >> sft; | |
495 | break; | |
496 | case SS_Registers::PR_TNPC: | |
497 | if (s->tl() == 0) | |
498 | return SS_Registers::NOT_AVAILABLE; | |
499 | *value = int64_t(s->tnpc() << sft) >> sft; | |
500 | break; | |
501 | case SS_Registers::PR_TSTATE: | |
502 | if (s->tl() == 0) | |
503 | return SS_Registers::NOT_AVAILABLE; | |
504 | *value = s->tstate(); | |
505 | break; | |
506 | case SS_Registers::PR_TT: | |
507 | if (s->tl() == 0) | |
508 | return SS_Registers::NOT_AVAILABLE; | |
509 | *value = s->tt(); | |
510 | break; | |
511 | case SS_Registers::HPR_HTSTATE: | |
512 | if (s->tl() == 0) | |
513 | return SS_Registers::NOT_AVAILABLE; | |
514 | *value = s->htstate(); | |
515 | break; | |
516 | ||
517 | default: | |
518 | return SS_Registers::NOT_AVAILABLE; | |
519 | } | |
520 | } | |
521 | return SS_Registers::OK; | |
522 | } | |
523 | /*}}}*/ | |
524 | SS_Registers::Error SS_Strand::ss_set_state( SS_Strand* s, SS_Registers::Index index, uint64_t value )/*{{{*/ | |
525 | { | |
526 | if (SS_Registers::is_irf(index)) | |
527 | { | |
528 | if (index != SS_Registers::G0) | |
529 | s->irf[index - SS_Registers::IRF_OFS] = value; | |
530 | } | |
531 | else if (SS_Registers::is_drf(index)) | |
532 | s->drf[index - SS_Registers::DRF_OFS] = value; | |
533 | else if (SS_Registers::is_frf(index)) | |
534 | s->get_frf(SS_Strand::freg_idx2off(index - SS_Registers::FRF_OFS)) = value; | |
535 | else | |
536 | { | |
537 | // For processors that do not implement the full 64bit for virtual address | |
538 | // we need to make sure that the unimplemented bits are sign extended based | |
539 | // on bit[va_bits() - 1]. This is done for pc, npc, tpc, tnpc, and also | |
540 | // tba, htba and rstv_addr. | |
541 | ||
542 | uint_t sft = 64 - s->va_bits(); | |
543 | ||
544 | switch (index) | |
545 | { | |
546 | case SS_Registers::ASR_Y: s->y.set(value); break; | |
547 | case SS_Registers::ASR_CCR: s->ccr.set(value); break; | |
548 | case SS_Registers::ASR_ASI: s->asi.set(value); break; | |
549 | case SS_Registers::ASR_TICK: s->tick.set(value); break; | |
550 | case SS_Registers::ASR_FPRS: s->fprs.set(value); break; | |
551 | case SS_Registers::ASR_GSR: s->gsr.set(value); break; | |
552 | case SS_Registers::ASR_TICK_CMPR: s->tick_cmpr.set(value); break; | |
553 | case SS_Registers::ASR_STICK: s->stick.set(value); break; | |
554 | case SS_Registers::ASR_STICK_CMPR: s->stick_cmpr.set(value); break; | |
555 | case SS_Registers::PR_TICK: s->tick.set(value); break; | |
556 | case SS_Registers::PR_TBA: s->tba.set(int64_t(value << sft) >> sft); break; | |
557 | case SS_Registers::PR_PSTATE: s->pstate.set(value); break; | |
558 | case SS_Registers::PR_CANSAVE: s->cansave.set(value); break; | |
559 | case SS_Registers::PR_CANRESTORE: s->canrestore.set(value); break; | |
560 | case SS_Registers::PR_CLEANWIN: s->cleanwin.set(value); break; | |
561 | case SS_Registers::PR_OTHERWIN: s->otherwin.set(value); break; | |
562 | case SS_Registers::PR_WSTATE: s->wstate.set(value); break; | |
563 | case SS_Registers::HPR_HPSTATE: s->hpstate.set(value); break; | |
564 | case SS_Registers::HPR_HTBA: s->htba.set(int64_t(value << sft) >> sft); break; | |
565 | case SS_Registers::HPR_HVER: s->hver.set(value); break; | |
566 | case SS_Registers::HPR_HSTICK_CMPR: s->hstick_cmpr.set(value); break; | |
567 | case SS_Registers::SIM_RSTV_ADDR: s->rstv_addr.set(int64_t(value << sft) >> sft); break; | |
568 | case SS_Registers::SIM_NPC: s->npc.set(int64_t(value << sft) >> sft); break; | |
569 | case SS_Registers::SIM_STATE: s->sim_state.set(value); break; | |
570 | case SS_Registers::SIM_INST_COUNT: s->inst_count.set(value); break; | |
571 | ||
572 | // When the PC is set from the front end then we clean all the | |
573 | // breakpoint related information that might be pending. This | |
574 | // means that when we do sim.s0.pc = sim.s0.pc then we will hit | |
575 | // the breakpoint on pc again if we just hit it. | |
576 | ||
577 | case SS_Registers::ASR_PC: | |
578 | s->skip_break_inst_va = false; | |
579 | if (s->break_hit) | |
580 | s->break_hit->triggered = false; | |
581 | s->break_hit = 0; | |
582 | s->pc.set(int64_t(value << sft) >> sft); | |
583 | break; | |
584 | ||
585 | case SS_Registers::PR_CWP: | |
586 | if (value > s->max_wp()) | |
587 | return SS_Registers::VALUE_OUT_OF_RANGE; | |
588 | s->cwp_save(); | |
589 | s->cwp.set(value); | |
590 | s->cwp_load(); | |
591 | break; | |
592 | ||
593 | case SS_Registers::PR_TL: | |
594 | if (value > s->max_tl()) | |
595 | return SS_Registers::VALUE_OUT_OF_RANGE; | |
596 | s->tl_save(); | |
597 | s->tl.set(value); | |
598 | s->tl_load(); | |
599 | break; | |
600 | ||
601 | case SS_Registers::PR_GL: | |
602 | if (value > s->max_gl()) | |
603 | return SS_Registers::VALUE_OUT_OF_RANGE; | |
604 | s->gl_save(); | |
605 | s->gl.set(value); | |
606 | s->gl_load(); | |
607 | break; | |
608 | ||
609 | case SS_Registers::SIM_FSR: | |
610 | s->fsr.set(value); | |
611 | s->set_fsr(); // ToDo: Why do I keep fsr if I have to do get/set_fsr ? | |
612 | break; | |
613 | ||
614 | case SS_Registers::PR_PIL: | |
615 | s->pil.set(value); | |
616 | s->irq.check(s); | |
617 | break; | |
618 | ||
619 | case SS_Registers::ASR_SOFTINT_SET: | |
620 | s->softint.set(s->softint() | value); | |
621 | s->irq.update_softint(s); | |
622 | break; | |
623 | ||
624 | case SS_Registers::ASR_SOFTINT_CLR: | |
625 | s->softint.set(s->softint() &~ value); | |
626 | s->irq.update_softint(s); | |
627 | break; | |
628 | ||
629 | case SS_Registers::ASR_SOFTINT: | |
630 | s->softint.set(value); | |
631 | s->irq.update_softint(s); | |
632 | break; | |
633 | ||
634 | case SS_Registers::HPR_HINTP: | |
635 | s->hintp.set(value); | |
636 | if (s->hintp.hsp()) | |
637 | s->irq.raise(s,SS_Interrupt::BIT_HSTICK_MATCH); | |
638 | else | |
639 | s->irq.retract(SS_Interrupt::BIT_HSTICK_MATCH); | |
640 | break; | |
641 | ||
642 | case SS_Registers::PR_TPC: | |
643 | if (s->tl() == 0) | |
644 | return SS_Registers::NOT_AVAILABLE; | |
645 | s->tpc.set(int64_t(value << sft) >> sft); | |
646 | break; | |
647 | case SS_Registers::PR_TNPC: | |
648 | if (s->tl() == 0) | |
649 | return SS_Registers::NOT_AVAILABLE; | |
650 | s->tnpc.set(int64_t(value << sft) >> sft); | |
651 | break; | |
652 | case SS_Registers::PR_TSTATE: | |
653 | if (s->tl() == 0) | |
654 | return SS_Registers::NOT_AVAILABLE; | |
655 | s->tstate.set(value); | |
656 | break; | |
657 | case SS_Registers::PR_TT: | |
658 | if (s->tl() == 0) | |
659 | return SS_Registers::NOT_AVAILABLE; | |
660 | s->tt.set(value); | |
661 | break; | |
662 | case SS_Registers::HPR_HTSTATE: | |
663 | if (s->tl() == 0) | |
664 | return SS_Registers::NOT_AVAILABLE; | |
665 | s->htstate.set(value); | |
666 | break; | |
667 | ||
668 | default: | |
669 | return SS_Registers::NOT_AVAILABLE; | |
670 | } | |
671 | } | |
672 | return SS_Registers::OK; | |
673 | } | |
674 | /*}}}*/ | |
675 | ||
676 | void SS_Strand::get_name( char* dst )/*{{{*/ | |
677 | { | |
678 | if (parent) | |
679 | { | |
680 | parent->get_name(dst); | |
681 | strcat(dst,"."); | |
682 | strcat(dst,name); | |
683 | } | |
684 | else | |
685 | strcpy(dst,name); | |
686 | } | |
687 | /*}}}*/ | |
688 | ||
689 | void SS_Strand::snapshot( SS_SnapShot& ss )/*{{{*/ | |
690 | { | |
691 | int i; | |
692 | char prefix[32]; | |
693 | ||
694 | get_name(prefix); | |
695 | ||
696 | if (ss.do_save()) | |
697 | { | |
698 | // Before we dump the strand state we save all the | |
699 | // duplicate state to get one coherent view of the strand. | |
700 | ||
701 | cwp_save(); | |
702 | gl_save(); | |
703 | tl_save(); | |
704 | get_fsr(); | |
705 | } | |
706 | ||
707 | // Save all the registers windows, | |
708 | ||
709 | for (int wp=0; wp <= max_wp(); wp++) | |
710 | { | |
711 | for (i=0; i<8; i++) | |
712 | { | |
713 | sprintf(ss.tag,"%s.wp.%d.l%d",prefix,wp,i); | |
714 | ss.val(&wrf[wp * 16 + i]); | |
715 | } | |
716 | for (i=0; i<8; i++) | |
717 | { | |
718 | sprintf(ss.tag,"%s.wp.%d.i%d",prefix,wp,i); | |
719 | ss.val(&wrf[wp * 16 + 8 + i]); | |
720 | } | |
721 | } | |
722 | ||
723 | // Save all the globals, | |
724 | ||
725 | for (int gp=0; gp <= max_gl(); gp++) | |
726 | { | |
727 | for (i=1; i<8; i++) // skip %g0 | |
728 | { | |
729 | sprintf(ss.tag,"%s.gl.%d.g%d",prefix,gp,i); | |
730 | ss.val(&grf[gp * 8 + i]); | |
731 | } | |
732 | } | |
733 | ||
734 | // Save all the doubles | |
735 | ||
736 | for (i=0; i < 32; i++) | |
737 | { | |
738 | sprintf(ss.tag,"%s.d%d",prefix,i); | |
739 | ss.val(&drf[i]); | |
740 | } | |
741 | ||
742 | // Save the trap stack (tl=0 is never used) | |
743 | ||
744 | for (int tp=1; tp <= max_tl(); tp++) | |
745 | { | |
746 | sprintf(ss.tag,"%s.tl.%d.pc",prefix,tp); ss.val(&trap_state[tp].pc); | |
747 | sprintf(ss.tag,"%s.tl.%d.npc",prefix,tp); ss.val(&trap_state[tp].npc); | |
748 | sprintf(ss.tag,"%s.tl.%d.tstate",prefix,tp); ss.val(&trap_state[tp].tstate); | |
749 | sprintf(ss.tag,"%s.tl.%d.htstate",prefix,tp); ss.val(&trap_state[tp].htstate); | |
750 | sprintf(ss.tag,"%s.tl.%d.tt",prefix,tp); ss.val(&trap_state[tp].tt); | |
751 | } | |
752 | ||
753 | // tpc, tnpc, tstat, htstate, and tt get saved/restored by tl_save()/tl_load() | |
754 | // respectively an that got save above. So we don't have to handle those here. | |
755 | ||
756 | sprintf(ss.tag,"%s.%s",prefix,pc.name()); pc.snapshot(ss); | |
757 | sprintf(ss.tag,"%s.%s",prefix,npc.name()); npc.snapshot(ss); | |
758 | sprintf(ss.tag,"%s.%s",prefix,gsr.name()); gsr.snapshot(ss); | |
759 | sprintf(ss.tag,"%s.%s",prefix,tick.name()); tick.snapshot(ss); | |
760 | sprintf(ss.tag,"%s.%s",prefix,stick.name()); stick.snapshot(ss); | |
761 | sprintf(ss.tag,"%s.%s",prefix,tick_cmpr.name()); tick_cmpr.snapshot(ss); | |
762 | sprintf(ss.tag,"%s.%s",prefix,stick_cmpr.name()); stick_cmpr.snapshot(ss); | |
763 | sprintf(ss.tag,"%s.%s",prefix,hstick_cmpr.name()); hstick_cmpr.snapshot(ss); | |
764 | sprintf(ss.tag,"%s.%s",prefix,softint.name()); softint.snapshot(ss); | |
765 | sprintf(ss.tag,"%s.%s",prefix,tba.name()); tba.snapshot(ss); | |
766 | sprintf(ss.tag,"%s.%s",prefix,htba.name()); htba.snapshot(ss); | |
767 | sprintf(ss.tag,"%s.%s",prefix,rstv_addr.name()); rstv_addr.snapshot(ss); | |
768 | sprintf(ss.tag,"%s.%s",prefix,hver.name()); hver.snapshot(ss); | |
769 | sprintf(ss.tag,"%s.%s",prefix,y.name()); y.snapshot(ss); | |
770 | sprintf(ss.tag,"%s.%s",prefix,pstate.name()); pstate.snapshot(ss); | |
771 | sprintf(ss.tag,"%s.%s",prefix,hpstate.name()); hpstate.snapshot(ss); | |
772 | sprintf(ss.tag,"%s.%s",prefix,sim_state.name()); sim_state.snapshot(ss); | |
773 | sprintf(ss.tag,"%s.%s",prefix,ccr.name()); ccr.snapshot(ss); | |
774 | sprintf(ss.tag,"%s.%s",prefix,asi.name()); asi.snapshot(ss); | |
775 | sprintf(ss.tag,"%s.%s",prefix,fprs.name()); fprs.snapshot(ss); | |
776 | sprintf(ss.tag,"%s.%s",prefix,tl.name()); tl.snapshot(ss); | |
777 | sprintf(ss.tag,"%s.%s",prefix,gl.name()); gl.snapshot(ss); | |
778 | sprintf(ss.tag,"%s.%s",prefix,cwp.name()); cwp.snapshot(ss); | |
779 | sprintf(ss.tag,"%s.%s",prefix,cansave.name()); cansave.snapshot(ss); | |
780 | sprintf(ss.tag,"%s.%s",prefix,canrestore.name()); canrestore.snapshot(ss); | |
781 | sprintf(ss.tag,"%s.%s",prefix,cleanwin.name()); cleanwin.snapshot(ss); | |
782 | sprintf(ss.tag,"%s.%s",prefix,otherwin.name()); otherwin.snapshot(ss); | |
783 | sprintf(ss.tag,"%s.%s",prefix,wstate.name()); wstate.snapshot(ss); | |
784 | sprintf(ss.tag,"%s.%s",prefix,pil.name()); pil.snapshot(ss); | |
785 | sprintf(ss.tag,"%s.%s",prefix,hintp.name()); hintp.snapshot(ss); | |
786 | sprintf(ss.tag,"%s.%s",prefix,fsr.name()); fsr.snapshot(ss); | |
787 | ||
788 | sprintf(ss.tag,"%s.halted",prefix); ss.val(&halted); | |
789 | ||
790 | sprintf(ss.tag,"%s.%s",prefix,"inst_dft_asi"); inst_dft_asi.snapshot(ss); | |
791 | sprintf(ss.tag,"%s.%s",prefix,"data_dft_asi"); data_dft_asi.snapshot(ss); | |
792 | ||
793 | for (int ps=0; ps < 8; ps++) | |
794 | { | |
795 | sprintf(ss.tag,"%s.scratch.%d",prefix,ps); | |
796 | ss.val(&scratchpad[ps]); | |
797 | } | |
798 | ||
799 | for (int hs=0; hs < 8; hs++) | |
800 | { | |
801 | sprintf(ss.tag,"%s.hscratch.%d",prefix,hs); | |
802 | ss.val(&hscratchpad[hs]); | |
803 | } | |
804 | ||
805 | irq.snapshot(ss,prefix); | |
806 | msg.snapshot(ss,prefix); | |
807 | ||
808 | if (ss.do_load()) | |
809 | { | |
810 | // Now restore the state that didn't get saved back to | |
811 | // sensible values. Flush the decode caches, and update | |
812 | // the simulator state (which decode cache to use etc) | |
813 | ||
814 | cwp_load(); | |
815 | gl_load(); | |
816 | tl_load(); | |
817 | set_fsr(); | |
818 | } | |
819 | ||
820 | // We flush the decode caches on snapshot, to make running | |
821 | // from saved snapshot behave identical to run after dump. | |
822 | ||
823 | flush_tte_all(); | |
824 | } | |
825 | /*}}}*/ | |
826 | ||
827 | SS_BreakPoint::Error SS_Strand::break_delete( SS_BreakPoint::Ident id )/*{{{*/ | |
828 | { | |
829 | SS_BreakPoint* prev = 0; | |
830 | ||
831 | break_hit = 0; | |
832 | ||
833 | for (SS_BreakPoint* self = break_points; self; self = self->next) | |
834 | { | |
835 | if (self->id == id) | |
836 | { | |
837 | (prev ? prev->next : break_points) = self->next; | |
838 | ||
839 | switch (self->type) | |
840 | { | |
841 | case SS_BreakPoint::ON_TRAP: | |
842 | self->unlink((SS_BreakPoint**)&break_trap[((SS_BreakTrap*)self)->tt]); | |
843 | break; | |
844 | case SS_BreakPoint::ON_RED_MODE: | |
845 | self->unlink((SS_BreakPoint**)&break_red_mode); | |
846 | break; | |
847 | case SS_BreakPoint::ON_INST_VA: | |
848 | self->unlink((SS_BreakPoint**)&break_inst_va); | |
849 | break; | |
850 | } | |
851 | delete self; | |
852 | return SS_BreakPoint::OK; | |
853 | } | |
854 | else | |
855 | prev = self; | |
856 | } | |
857 | return SS_BreakPoint::ID_UNKNOWN; | |
858 | } | |
859 | /*}}}*/ | |
860 | SS_BreakPoint::Error SS_Strand::break_enable( SS_BreakPoint::Ident id )/*{{{*/ | |
861 | { | |
862 | for (SS_BreakPoint* self = break_points; self; self = self->next) | |
863 | { | |
864 | if (self->id == id) | |
865 | { | |
866 | self->enabled = true; | |
867 | return SS_BreakPoint::OK; | |
868 | } | |
869 | } | |
870 | return SS_BreakPoint::ID_UNKNOWN; | |
871 | } | |
872 | /*}}}*/ | |
873 | SS_BreakPoint::Error SS_Strand::break_disable( SS_BreakPoint::Ident id )/*{{{*/ | |
874 | { | |
875 | for (SS_BreakPoint* self = break_points; self; self = self->next) | |
876 | { | |
877 | if (self->id == id) | |
878 | { | |
879 | self->enabled = false; | |
880 | return SS_BreakPoint::OK; | |
881 | } | |
882 | } | |
883 | return SS_BreakPoint::ID_UNKNOWN; | |
884 | } | |
885 | /*}}}*/ | |
886 | SS_BreakPoint::Ident SS_Strand::break_on_trap( uint_t _tt )/*{{{*/ | |
887 | { | |
888 | SS_BreakTrap* bp = new SS_BreakTrap(SS_Trap::Type(_tt),break_points); | |
889 | break_points = bp; | |
890 | bp->link = break_trap[_tt]; | |
891 | break_trap[_tt] = bp; | |
892 | return bp->id; | |
893 | } | |
894 | /*}}}*/ | |
895 | SS_BreakPoint::Ident SS_Strand::break_on_red_mode()/*{{{*/ | |
896 | { | |
897 | SS_BreakRedMode* bp = new SS_BreakRedMode(break_points); | |
898 | break_points = bp; | |
899 | bp->link = break_red_mode; | |
900 | break_red_mode = bp; | |
901 | return bp->id; | |
902 | } | |
903 | /*}}}*/ | |
904 | SS_BreakPoint::Ident SS_Strand::break_on_inst_va( SS_Vaddr va )/*{{{*/ | |
905 | { | |
906 | flush_va(va); | |
907 | SS_BreakInstVa* bp = new SS_BreakInstVa(va,break_points); | |
908 | break_points = bp; | |
909 | bp->link = break_inst_va; | |
910 | break_inst_va = bp; | |
911 | return bp->id; | |
912 | } | |
913 | /*}}}*/ | |
914 | ||
915 | void SS_Strand::tl_save()/*{{{*/ | |
916 | { | |
917 | TrapState* p = &trap_state[tl()]; | |
918 | ||
919 | p->pc = tpc(); | |
920 | p->npc = tnpc(); | |
921 | p->tstate = tstate(); | |
922 | p->htstate = htstate(); | |
923 | p->tt = tt(); | |
924 | } | |
925 | /*}}}*/ | |
926 | void SS_Strand::tl_load()/*{{{*/ | |
927 | { | |
928 | TrapState* p = &trap_state[tl()]; | |
929 | ||
930 | tpc = p->pc; | |
931 | tnpc = p->npc; | |
932 | tstate = p->tstate; | |
933 | htstate = p->htstate; | |
934 | tt = p->tt; | |
935 | } | |
936 | /*}}}*/ | |
937 | ||
938 | void SS_Strand::merge_asi_map()/*{{{*/ | |
939 | { | |
940 | parent->merge_asi_map(asi_map); | |
941 | } | |
942 | /*}}}*/ | |
943 | ||
944 | void SS_Strand::ss_sim_update( SS_Strand* s )/*{{{*/ | |
945 | { | |
946 | // This routine is the main routine to keep all our fancy caches and | |
947 | // things in sync and do special things only when they need to be done. | |
948 | // (sim_update)(me) should get called whenever a state change happens | |
949 | // that requires switching decode caches ets. E.g we track changes to | |
950 | // pstate, hpstate, tl, fprs.fef (fpr fpu enabled), softint in | |
951 | // combination with pstate.ie, and lsu_ctr (if used), etc. | |
952 | ||
953 | bool inst_cache_flush = false; | |
954 | uint64_t prev_priv = s->sim_state.priv(); | |
955 | ||
956 | // First figure out which privileged level we're at. Additionally, | |
957 | // to safe tests, we check whether interrupts are enabled and allowed | |
958 | // and whether trap level zero traps should be thrown. | |
959 | ||
960 | if (s->hpstate.hpriv()) | |
961 | { | |
962 | s->sim_state.priv(SS_HPRV); | |
963 | ||
964 | // Some processor implement crosscall with interrupt_vector_trap | |
965 | // that can be blocked in hypervisor by pstate.ie ... so if we're | |
966 | // here and ca can deal with them ... just checking. | |
967 | ||
968 | if (s->pstate.ie()) | |
969 | s->irq.check(s); | |
970 | } | |
971 | else | |
972 | { | |
973 | if (s->pstate.priv()) | |
974 | s->sim_state.priv(SS_PRIV); | |
975 | else | |
976 | s->sim_state.priv(SS_USER); | |
977 | ||
978 | // Check for trap level zero condition here first. Launch a disrupting | |
979 | // tlz trap when the tlz condition arises: note TLZ has high priority! | |
980 | ||
981 | if (!s->irq.is_pending(SS_Interrupt::BIT_TRAP_LEVEL_ZERO) && s->hpstate.tlz() && (s->tl() == 0)) | |
982 | s->irq.raise(s,SS_Interrupt::BIT_TRAP_LEVEL_ZERO); | |
983 | else | |
984 | s->irq.check(s); | |
985 | } | |
986 | ||
987 | // Figure out which decode cache to use. We use multiple caches to | |
988 | // allow a better hit rate and to safe on privileged checks in critical | |
989 | // code (mainly memory ops). For ra2pa and va2pa we add extra decode | |
990 | // caches to differentiate the used default data asi. | |
991 | // We set the inst_mmu to the one with the correct translation mode. | |
992 | // | |
993 | // ToDo: perhaps we should keep the default data asi in the instruction | |
994 | // cache so that the primary/nuclues can be folded into one and the | |
995 | // little/big endian default asi test can use that too. Additionally | |
996 | // we should do some performance analisys to see which modes are mainly | |
997 | // used under solaris so that we can proper optimize for those, and | |
998 | // use flushing for others. 9 decode caches is a little much ... | |
999 | // Alternatively we might want to 'cache' a few context's ... so | |
1000 | // that we can keep a few users alive ... need to investigate context | |
1001 | // switch patters on s10 boot and application run | |
1002 | ||
1003 | if ((s->sim_state.priv() == SS_HPRV) || s->hpstate.red()) | |
1004 | { | |
1005 | s->inst_mmu = s->inst_mmu_pa; | |
1006 | s->inst_ctx = s->inst_ctx_pa; | |
1007 | ||
1008 | s->inst_cache = s->inst_cache_pa; | |
1009 | ||
1010 | // We don't detect context switches in hyperprivileged mode. | |
1011 | // This means that we have to be carefull when caching data | |
1012 | // TTEs. In general when we are in hyperprivileged mode and | |
1013 | // the data mmu is not bypassing, the we don't cache the TTE. | |
1014 | } | |
1015 | else | |
1016 | { | |
1017 | if (!s->sim_state.inst_mmu()) | |
1018 | { | |
1019 | s->inst_mmu = s->inst_mmu_ra; | |
1020 | s->inst_ctx = s->inst_ctx_ra; | |
1021 | ||
1022 | if (s->sim_state.priv() == SS_PRIV) | |
1023 | { | |
1024 | if (s->tl()) | |
1025 | s->inst_cache = s->inst_cache_ra_nuc_priv; | |
1026 | else | |
1027 | s->inst_cache = s->inst_cache_ra_pri_priv; | |
1028 | } | |
1029 | else | |
1030 | { | |
1031 | if (s->tl()) | |
1032 | s->inst_cache = s->inst_cache_ra_nuc_user; | |
1033 | else | |
1034 | s->inst_cache = s->inst_cache_ra_pri_user; | |
1035 | } | |
1036 | } | |
1037 | else | |
1038 | { | |
1039 | s->inst_mmu = s->inst_mmu_va; | |
1040 | s->inst_ctx = s->inst_ctx_va; | |
1041 | ||
1042 | if (s->sim_state.priv() == SS_PRIV) | |
1043 | { | |
1044 | if (s->tl() || (s->inst_ctx.get_pri() == 0)) | |
1045 | { | |
1046 | if (s->data_ctx.get() == 0) | |
1047 | s->inst_cache = s->inst_cache_va_nuc_nuc_nuc_priv; | |
1048 | else if (s->data_ctx.get_pri() == 0) | |
1049 | s->inst_cache = s->inst_cache_va_nuc_nuc_sec_priv; | |
1050 | else | |
1051 | s->inst_cache = s->inst_cache_va_nuc_pri_sec_priv; | |
1052 | } | |
1053 | else | |
1054 | s->inst_cache = s->inst_cache_va_pri_priv; | |
1055 | } | |
1056 | else | |
1057 | { | |
1058 | if (s->tl()) | |
1059 | s->inst_cache = s->inst_cache_va_nuc_user; | |
1060 | else | |
1061 | s->inst_cache = s->inst_cache_va_pri_user; | |
1062 | } | |
1063 | } | |
1064 | ||
1065 | if (s->inst_cache->data_ctx.get() != s->data_ctx.get()) | |
1066 | { | |
1067 | //fprintf(stderr,"CSD: %6s %d %d %016llx\n",s->inst_cache->id,s->sim_state.mode(),s->tl(),s->data_ctx.get()); | |
1068 | s->inst_cache->data_ctx = s->data_ctx; | |
1069 | inst_cache_flush = true; | |
1070 | } | |
1071 | } | |
1072 | ||
1073 | ||
1074 | // In red state we only use one decode cache as it's a rare state, | |
1075 | // the same one as in hyper privileged mode (for pa->pa immu). | |
1076 | // Note that we can be at user, privileged or hyper privileged level | |
1077 | // and be in red state. Thus when we enter or leave the red state | |
1078 | // or when privilege level changes whilst in red state, or when TL | |
1079 | // changes between zero and non-zero the decode cache is flushed. | |
1080 | // Additionally keep track of whether we entered red mode or not so | |
1081 | // that we can check breakpoints on red mode entry. | |
1082 | ||
1083 | if (s->hpstate.red()) | |
1084 | { | |
1085 | if (!s->sim_state.red()) | |
1086 | { | |
1087 | s->sim_state.red(1); | |
1088 | inst_cache_flush = true; | |
1089 | ||
1090 | for (SS_BreakPoint* bp = s->break_red_mode; bp; bp = bp->link) | |
1091 | if (bp->enabled && bp->trigger(s)) | |
1092 | bp->trigger(s); | |
1093 | } | |
1094 | else if ((prev_priv != s->sim_state.priv()) | |
1095 | || ((s->tl() == 0) && (s->sim_state.red_tl() != 0)) | |
1096 | || ((s->tl() != 0) && (s->sim_state.red_tl() == 0))) | |
1097 | { | |
1098 | inst_cache_flush = true; | |
1099 | } | |
1100 | s->sim_state.red_tl(s->tl()); | |
1101 | } | |
1102 | else | |
1103 | { | |
1104 | if (s->sim_state.red()) | |
1105 | { | |
1106 | s->sim_state.red(0); | |
1107 | inst_cache_flush = true; | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | // Set the default asi used for fetch and load/store operations | |
1112 | ||
1113 | if (s->tl()) | |
1114 | { | |
1115 | s->inst_dft_asi = SS_Asi::ASI_NUCLEUS; | |
1116 | s->data_dft_asi = s->pstate.cle() ? SS_Asi::ASI_NUCLEUS_LITTLE : SS_Asi::ASI_NUCLEUS; | |
1117 | } | |
1118 | else | |
1119 | { | |
1120 | s->inst_dft_asi = SS_Asi::ASI_PRIMARY; | |
1121 | s->data_dft_asi = s->pstate.cle() ? SS_Asi::ASI_PRIMARY_LITTLE : SS_Asi::ASI_PRIMARY; | |
1122 | } | |
1123 | ||
1124 | // If the default data asi used in the instr cache changed from big to little | |
1125 | // or from little to big we flush the inst cache so that all load and stores | |
1126 | // with default asi pick up the correct asi value. | |
1127 | ||
1128 | if (s->inst_cache->pstate_cle_flag != s->pstate.cle()) | |
1129 | { | |
1130 | s->inst_cache->pstate_cle_flag = s->pstate.cle(); | |
1131 | inst_cache_flush = true; | |
1132 | } | |
1133 | ||
1134 | // Keep track of whether we used 32bit mode or 64bit mode when | |
1135 | // fetching and excuting instructions. If the mode changed compared | |
1136 | // to the previous time the cache was used mode then we flush the cache. | |
1137 | // Note we have to do this mainly because we cache inst and data TTEs. | |
1138 | ||
1139 | if (s->inst_cache->pstate_am_flag != s->pstate.am()) | |
1140 | { | |
1141 | s->inst_cache->pstate_am_flag = s->pstate.am(); | |
1142 | inst_cache_flush = true; | |
1143 | } | |
1144 | ||
1145 | // Keep track of whether pstate.tct was set or not, and if there | |
1146 | // is a change then flush the decode cache in question. The new | |
1147 | // decoded instruction will chech the pstate.tct bit and launch | |
1148 | // transfer control traps when apropriate. | |
1149 | ||
1150 | if (s->inst_cache->pstate_tct_flag != s->pstate.tct()) | |
1151 | { | |
1152 | s->inst_cache->pstate_tct_flag = s->pstate.tct(); | |
1153 | inst_cache_flush = true; | |
1154 | } | |
1155 | ||
1156 | // Keep track of whether hpstate.ibe was set or not, and if there | |
1157 | // is a change then flush the decode cache in question and use a | |
1158 | // decoder that checks the opcode for match before decoding. | |
1159 | ||
1160 | if (s->hpstate.ibe() || s->sim_state.ibe_sig()) | |
1161 | { | |
1162 | s->sim_state.ib_enabled(1); | |
1163 | ||
1164 | if (!s->inst_cache->hpstate_ibe_flag) | |
1165 | { | |
1166 | s->inst_cache->hpstate_ibe_flag = true; | |
1167 | inst_cache_flush = true; | |
1168 | } | |
1169 | } | |
1170 | else | |
1171 | { | |
1172 | s->sim_state.ib_enabled(0); | |
1173 | ||
1174 | if (s->inst_cache->hpstate_ibe_flag) | |
1175 | { | |
1176 | s->inst_cache->hpstate_ibe_flag = false; | |
1177 | inst_cache_flush = true; | |
1178 | } | |
1179 | } | |
1180 | ||
1181 | // Switch the decoder if ib enabled | |
1182 | ||
1183 | if (s->sim_state.ib_enabled()) | |
1184 | { | |
1185 | // Some products, like N2 for example reversed the instruction | |
1186 | // breakpoint and illegal instruction trap priority. For those | |
1187 | // products the decode functions do the checks all over the place. | |
1188 | // For product that are as SunSparc specifies we can simply flip | |
1189 | // the main decoder, e.g. check before you really decode. The | |
1190 | // others require a decode cache flush so that we go through the | |
1191 | // decode routines again. Some processors have no hpstate.ibe. | |
1192 | // These will have to use the SS_Signal::SET_INST_BRKPT method. | |
1193 | if (SS_Trap::table[SS_Trap::INSTRUCTION_BREAKPOINT].priority < | |
1194 | SS_Trap::table[SS_Trap::ILLEGAL_INSTRUCTION].priority) | |
1195 | { | |
1196 | s->inst_dec = ss_ibe_dec; | |
1197 | s->save_dec = ss_ibe_dec; | |
1198 | } | |
1199 | } | |
1200 | else | |
1201 | { | |
1202 | s->inst_dec = ss_run_dec; | |
1203 | s->save_dec = ss_run_dec; | |
1204 | } | |
1205 | ||
1206 | // Nuke the tte pointers in the current decode cache so that we | |
1207 | // start from fresh, as previous cached contents is likely invalid. | |
1208 | ||
1209 | if (inst_cache_flush) | |
1210 | { | |
1211 | for (int l=0; l < SS_InstrCache::SIZE; l++) | |
1212 | s->inst_cache->tag[l].tte = &::junk_tte; | |
1213 | } | |
1214 | ||
1215 | // Check for fpu enabled or not. We throw the two flags into | |
1216 | // a single flag to make check for enabled fpu easier and faster. | |
1217 | // | |
1218 | // ToDo the disabled check should be part of decode and we | |
1219 | // should flush the decode cache on enable/disable. This so that | |
1220 | // we can finish a proper ill_ibe implementation. | |
1221 | ||
1222 | if (s->sim_state.fp_disabled()) | |
1223 | { | |
1224 | if (s->fprs.fef() && s->pstate.pef()) | |
1225 | s->sim_state.fp_disabled(0); | |
1226 | } | |
1227 | else | |
1228 | { | |
1229 | if (!(s->fprs.fef() && s->pstate.pef())) | |
1230 | s->sim_state.fp_disabled(1); | |
1231 | } | |
1232 | ||
1233 | // Set the current address mask value to be used (v8 compatible mode) | |
1234 | ||
1235 | if (s->pstate.am()) | |
1236 | s->mask_pstate_am = ~uint32_t(0); | |
1237 | else | |
1238 | s->mask_pstate_am = ~uint64_t(0); | |
1239 | ||
1240 | // Make sure the first executed instruction does check the cached TTE or | |
1241 | // does a lookup in the TLB. | |
1242 | ||
1243 | s->inst_tte = s->fail_tte; | |
1244 | ||
1245 | // Now send a message that we need to exit the inner run_loop, and | |
1246 | // reenter if we need to execute more code. This is to propagate | |
1247 | // the configuration that was setup above. | |
1248 | ||
1249 | s->msg.set_reenter_loop(); | |
1250 | } | |
1251 | /*}}}*/ | |
1252 | void SS_Strand::set_fsr()/*{{{*/ | |
1253 | { | |
1254 | // For hardware floating point emulation we keep more then one version of the | |
1255 | // frs around. The fsr_run is the %fsr being used for the hardware floating | |
1256 | // point instruction. It has the tem=0 so traps don't occur during execution of | |
1257 | // the hardware floating point instruction, and aexc and cexc are cleared so | |
1258 | // we can find out if a trap occured. The simulated fsr.tem bits are kept in | |
1259 | // fsr_tem and the simulated fsr.eaxc and fsr.cexc are kept in fsr_exc. | |
1260 | // The final simulated fsr is composed by get_fsr(). | |
1261 | ||
1262 | fsr_run = fsr(); | |
1263 | ||
1264 | fsr_run.tem(0); // clear tem field so we don't take traps | |
1265 | fsr_run.cexc(0); | |
1266 | fsr_run.aexc(0); | |
1267 | fsr_tem = 0; | |
1268 | fsr_tem.cexc(fsr.tem()); // put tem field in cexc so we don;t have to shift it | |
1269 | fsr_exc = 0; | |
1270 | fsr_exc.cexc(fsr.cexc()); | |
1271 | fsr_exc.aexc(fsr.aexc()); | |
1272 | } | |
1273 | /*}}}*/ | |
1274 | void SS_Strand::get_fsr()/*{{{*/ | |
1275 | { | |
1276 | fsr.ftt(fsr_run.ftt()); | |
1277 | fsr.aexc(fsr_exc.aexc()); | |
1278 | fsr.cexc(fsr_exc.cexc()); | |
1279 | } | |
1280 | /*}}}*/ | |
1281 | ||
1282 | void SS_Strand::setup_tte_link_tables()/*{{{*/ | |
1283 | { | |
1284 | inst_tte_link = new SS_Chain[inst_tlb->size()]; | |
1285 | inst_tte_link_size = inst_tlb->size(); | |
1286 | data_tte_link = new SS_Chain[data_tlb->size()]; | |
1287 | data_tte_link_size = data_tlb->size(); | |
1288 | } | |
1289 | /*}}}*/ | |
1290 | ||
1291 | void SS_Strand::flush_tte( SS_Tlb* tlb, SS_Tte* tte )/*{{{*/ | |
1292 | { | |
1293 | assert (tte); | |
1294 | ||
1295 | // Note a tlb can be both inst and data tlb. So when we flush a | |
1296 | // tte from the decode cache we have to be carefull and check | |
1297 | // both inst and data flavors. | |
1298 | ||
1299 | if (tlb->is_data_tlb()) | |
1300 | { | |
1301 | SS_Chain* head = &data_tte_link[tte->index]; | |
1302 | for (SS_Chain* next = head->next; head != next; next = next->next) | |
1303 | { | |
1304 | char* ptr_tag = (char*)next - ptr_ofs(SS_Instr,lnk) + ptr_ofs(SS_Instr,tte); | |
1305 | ((SS_InstrCache::Tag*)ptr_tag)->tte = &::junk_tte; | |
1306 | } | |
1307 | head->unlink(); | |
1308 | head->clean(); | |
1309 | } | |
1310 | ||
1311 | if (tlb->is_inst_tlb()) | |
1312 | { | |
1313 | SS_Chain* head = &inst_tte_link[tte->index]; | |
1314 | for (SS_Chain* next = head->next; head != next; next = next->next) | |
1315 | { | |
1316 | char* ptr_tag = (char*)next - ptr_ofs(SS_InstrCache::Tag,lnk); | |
1317 | ((SS_InstrCache::Tag*)ptr_tag)->tte = &::junk_tte; | |
1318 | } | |
1319 | head->unlink(); | |
1320 | head->clean(); | |
1321 | } | |
1322 | ||
1323 | // Make sure we also clear the current used TTE by the inst_mmu. | |
1324 | // Not doing so will create a timing window in the inst_mmu in which | |
1325 | // a TTE can be reinserted after flush. | |
1326 | ||
1327 | if (inst_tte == tte) | |
1328 | inst_tte = fail_tte; | |
1329 | ||
1330 | // Give the tte back when we are not in cosim mode | |
1331 | ||
1332 | if (!sim_state.cosim()) | |
1333 | tlb->reuse_tte(tte); | |
1334 | } | |
1335 | /*}}}*/ | |
1336 | ||
1337 | void SS_Strand::inst_tlb_set( SS_Tlb* tlb )/*{{{*/ | |
1338 | { | |
1339 | assert(sim_state.cosim()); | |
1340 | ||
1341 | if (inst_tlb != tlb) | |
1342 | { | |
1343 | flush_tte_all(); | |
1344 | } | |
1345 | ||
1346 | inst_tlb = tlb; | |
1347 | } | |
1348 | /*}}}*/ | |
1349 | ||
1350 | void SS_Strand::flush_tte_all()/*{{{*/ | |
1351 | { | |
1352 | // Flushes all used inst TTEs from the decode caches. | |
1353 | // This automatically invalidates all cached data TTEs. | |
1354 | ||
1355 | // First wipe out all va2pa and ra2pa TTE's | |
1356 | ||
1357 | for (uint_t i=0; i < inst_tte_link_size; i++) | |
1358 | { | |
1359 | SS_Chain* head = &inst_tte_link[i]; | |
1360 | SS_Chain* next = head->next; | |
1361 | ||
1362 | if (head != next) | |
1363 | { | |
1364 | while (head != next) | |
1365 | { | |
1366 | char* ptr_tag = (char*)next - ptr_ofs(SS_InstrCache::Tag,lnk); | |
1367 | ((SS_InstrCache::Tag*)ptr_tag)->tte = &::junk_tte; | |
1368 | next = next->next; | |
1369 | } | |
1370 | head->unlink(); | |
1371 | head->clean(); | |
1372 | } | |
1373 | } | |
1374 | ||
1375 | // For the pa2pa decode cache we keep a single link, just | |
1376 | // for the pedantic flush instruction's purpose. | |
1377 | ||
1378 | SS_Chain* next = phys_tte_link.next; | |
1379 | if (&phys_tte_link != next) | |
1380 | { | |
1381 | while (&phys_tte_link != next) | |
1382 | { | |
1383 | char* ptr_tag = (char*)next - ptr_ofs(SS_InstrCache::Tag,lnk); | |
1384 | ((SS_InstrCache::Tag*)ptr_tag)->tte = &::junk_tte; | |
1385 | next = next->next; | |
1386 | } | |
1387 | phys_tte_link.unlink(); | |
1388 | phys_tte_link.clean(); | |
1389 | } | |
1390 | ||
1391 | // In case of separate inst and data tlb we can remove all data TTE links | |
1392 | // without looking as we have removed all instructions from the decode | |
1393 | // cache, e.g. all cached instructions are now invalid. | |
1394 | ||
1395 | if (inst_tlb != data_tlb) | |
1396 | { | |
1397 | for (uint_t i=0; i < data_tte_link_size; i++) | |
1398 | { | |
1399 | SS_Chain* head = &data_tte_link[i]; | |
1400 | SS_Chain* next = head->next; | |
1401 | ||
1402 | if (head != next) | |
1403 | { | |
1404 | data_tte_link[i].unlink(); | |
1405 | data_tte_link[i].clean(); | |
1406 | } | |
1407 | } | |
1408 | } | |
1409 | ||
1410 | inst_tte = fail_tte; | |
1411 | } | |
1412 | /*}}}*/ | |
1413 | void SS_Strand::flush_va( SS_Vaddr ea )/*{{{*/ | |
1414 | { | |
1415 | // This routine implements flush for va watchpoints and breakpoints. | |
1416 | ||
1417 | uint_t line = (ea >> (SS_InstrCache::LINE_BITS + 2)) & SS_InstrCache::MASK; | |
1418 | ||
1419 | inst_cache_va_pri_user->tag[line].tte = &::junk_tte; | |
1420 | inst_cache_va_nuc_user->tag[line].tte = &::junk_tte; | |
1421 | inst_cache_va_pri_priv->tag[line].tte = &::junk_tte; | |
1422 | inst_cache_va_nuc_nuc_nuc_priv->tag[line].tte = &::junk_tte; | |
1423 | inst_cache_va_nuc_nuc_sec_priv->tag[line].tte = &::junk_tte; | |
1424 | inst_cache_va_nuc_pri_sec_priv->tag[line].tte = &::junk_tte; | |
1425 | inst_cache_ra_pri_user->tag[line].tte = &::junk_tte; | |
1426 | inst_cache_ra_nuc_user->tag[line].tte = &::junk_tte; | |
1427 | inst_cache_ra_pri_priv->tag[line].tte = &::junk_tte; | |
1428 | inst_cache_ra_nuc_priv->tag[line].tte = &::junk_tte; | |
1429 | inst_cache_pa->tag[line].tte = &::junk_tte; | |
1430 | ||
1431 | inst_tte = fail_tte; | |
1432 | } | |
1433 | /*}}}*/ | |
1434 | void SS_Strand::flush( SS_Paddr pa, bool for_ras )/*{{{*/ | |
1435 | { | |
1436 | // This routine implements flush as sun sparc specifies. E.g. the | |
1437 | // flush instruction flushes 8 bytes from the caches at the given | |
1438 | // effective address ea. However, currently no product uses this, we just | |
1439 | // flush the whole decode cache instead. | |
1440 | ||
1441 | // The routine is mainly used from the frontend when user write code to | |
1442 | // memory. | |
1443 | ||
1444 | assert(!for_ras || sim_state.ras_enabled()); | |
1445 | ||
1446 | pa >>= (SS_InstrCache::LINE_BITS + 2); | |
1447 | ||
1448 | uint_t line = pa & SS_InstrCache::MASK; | |
1449 | ||
1450 | if (for_ras) | |
1451 | inst_cache_pa->tag[line].tte_bits |= RAS_TTE_POISON; | |
1452 | else | |
1453 | inst_cache_pa->tag[line].tte = &::junk_tte; | |
1454 | ||
1455 | // The smallest pages size is 8KB so we loop through the caches | |
1456 | // in 8KB increments and invalidate the virtual TTEs. Note that we | |
1457 | // take the cacheline size into account. Since we flush a PA we | |
1458 | // need to make sure we hit all the aliases. | |
1459 | // | |
1460 | // Note, if flush causes more decode then we can consider keeping the | |
1461 | // PA of the cacheline as well and do a check before we flush. | |
1462 | // Also we do a lot of storing here, that's bound to be bad for L2. | |
1463 | // Is there a better way of doing this flush ... | |
1464 | ||
1465 | const uint_t size8k = 8192 >> (SS_InstrCache::LINE_BITS + 2); | |
1466 | const uint_t mask8k = size8k - 1; | |
1467 | ||
1468 | line = pa & mask8k; | |
1469 | ||
1470 | if (for_ras) | |
1471 | { | |
1472 | for (; line < SS_InstrCache::SIZE; line += size8k) | |
1473 | { | |
1474 | inst_cache_va_pri_user->tag[line].tte_bits |= RAS_TTE_POISON; | |
1475 | inst_cache_va_nuc_user->tag[line].tte_bits |= RAS_TTE_POISON; | |
1476 | inst_cache_va_pri_priv->tag[line].tte_bits |= RAS_TTE_POISON; | |
1477 | inst_cache_va_nuc_nuc_nuc_priv->tag[line].tte_bits |= RAS_TTE_POISON; | |
1478 | inst_cache_va_nuc_nuc_sec_priv->tag[line].tte_bits |= RAS_TTE_POISON; | |
1479 | inst_cache_va_nuc_pri_sec_priv->tag[line].tte_bits |= RAS_TTE_POISON; | |
1480 | inst_cache_ra_pri_user->tag[line].tte_bits |= RAS_TTE_POISON; | |
1481 | inst_cache_ra_nuc_user->tag[line].tte_bits |= RAS_TTE_POISON; | |
1482 | inst_cache_ra_pri_priv->tag[line].tte_bits |= RAS_TTE_POISON; | |
1483 | inst_cache_ra_nuc_priv->tag[line].tte_bits |= RAS_TTE_POISON; | |
1484 | } | |
1485 | } | |
1486 | else | |
1487 | { | |
1488 | for (; line < SS_InstrCache::SIZE; line += size8k) | |
1489 | { | |
1490 | inst_cache_va_pri_user->tag[line].tte = &::junk_tte; | |
1491 | inst_cache_va_nuc_user->tag[line].tte = &::junk_tte; | |
1492 | inst_cache_va_pri_priv->tag[line].tte = &::junk_tte; | |
1493 | inst_cache_va_nuc_nuc_nuc_priv->tag[line].tte = &::junk_tte; | |
1494 | inst_cache_va_nuc_nuc_sec_priv->tag[line].tte = &::junk_tte; | |
1495 | inst_cache_va_nuc_pri_sec_priv->tag[line].tte = &::junk_tte; | |
1496 | inst_cache_ra_pri_user->tag[line].tte = &::junk_tte; | |
1497 | inst_cache_ra_nuc_user->tag[line].tte = &::junk_tte; | |
1498 | inst_cache_ra_pri_priv->tag[line].tte = &::junk_tte; | |
1499 | inst_cache_ra_nuc_priv->tag[line].tte = &::junk_tte; | |
1500 | } | |
1501 | } | |
1502 | ||
1503 | inst_tte = fail_tte; | |
1504 | } | |
1505 | /*}}}*/ | |
1506 | ||
1507 | void SS_Strand::do_retry()/*{{{*/ | |
1508 | { | |
1509 | assert(tl()); | |
1510 | tl_save(); | |
1511 | ||
1512 | pc = tpc(); | |
1513 | npc = tnpc(); | |
1514 | ccr = tstate.ccr(); | |
1515 | asi = tstate.asi(); | |
1516 | pstate = tstate.pstate(); | |
1517 | hpstate = htstate.hpstate(); | |
1518 | ||
1519 | if (cwp() != tstate.cwp()) | |
1520 | { | |
1521 | cwp_save(); | |
1522 | cwp = tstate.cwp(); | |
1523 | cwp_load(); | |
1524 | } | |
1525 | ||
1526 | if (gl() != tstate.gl()) | |
1527 | { | |
1528 | gl_save(); | |
1529 | gl = tstate.gl(); | |
1530 | gl_load(); | |
1531 | } | |
1532 | if (!hpstate.hpriv() && (gl() > max_pgl())) | |
1533 | { | |
1534 | gl_save(); | |
1535 | gl = max_pgl(); | |
1536 | gl_load(); | |
1537 | } | |
1538 | ||
1539 | tl = tl() - 1; | |
1540 | tl_load(); | |
1541 | (sim_update)(this); | |
1542 | } | |
1543 | /*}}}*/ | |
1544 | ||
1545 | bool SS_Strand::peek_signal()/*{{{*/ | |
1546 | { | |
1547 | SS_Trap::Type trap_type = msg.get_handle_trap(); | |
1548 | ||
1549 | msg.clr_reenter_loop(); | |
1550 | ||
1551 | if (trap_type != SS_Trap::RESERVED) | |
1552 | { | |
1553 | assert(!halted); // An interrupt should wake us up. | |
1554 | msg.clr_handle_trap(); | |
1555 | (trap)(pc(),npc(),this,0,trap_type); | |
1556 | } | |
1557 | ||
1558 | while (msg.test_signal()) | |
1559 | { | |
1560 | SS_Signal* sgn = msg.get_signal(); | |
1561 | ||
1562 | switch (sgn->type) | |
1563 | { | |
1564 | case SS_Signal::BREAKPOINT: | |
1565 | break_hit = sgn->breakpoint; | |
1566 | return true; | |
1567 | ||
1568 | case SS_Signal::FLUSH_TTE: | |
1569 | flush_tte(sgn->tlb,sgn->tte); | |
1570 | break; | |
1571 | ||
1572 | case SS_Signal::FLUSH_VA: | |
1573 | // Called on say inst va watchpoint enable, need to make sure | |
1574 | // we will hit the watchpoint, so flush the decode cache and | |
1575 | // ensure we go through the mmu lookup again to check watchpoint. | |
1576 | flush_va(sgn->flush_va); | |
1577 | break; | |
1578 | ||
1579 | case SS_Signal::FLUSH_8B: | |
1580 | // FLUSH_PA flushes the decode cache lines that could map the pa | |
1581 | flush(sgn->flush_pa); | |
1582 | break; | |
1583 | ||
1584 | case SS_Signal::FLUSH_8K: | |
1585 | case SS_Signal::FLUSH_ALL: | |
1586 | // FLUSH_8K flushes the whole decode cache | |
1587 | flush_tte_all(); | |
1588 | break; | |
1589 | ||
1590 | case SS_Signal::SET_INST_BRKPT: | |
1591 | // Processors that have no hpstate.ibe bit switch to instruction | |
1592 | // breakpointing this way. Every time it gets enabled we flush the | |
1593 | // decode cache, to make sure we redecode all teh instructions. | |
1594 | sim_state.ibe_sig(sgn->ib_enable); | |
1595 | (sim_update)(this); | |
1596 | break; | |
1597 | ||
1598 | case SS_Signal::RUNNING: | |
1599 | // In cosim we always have all strands registered with the TLB as | |
1600 | // we can have tlb syncing (copy TLB) going on which complicates | |
1601 | // management of the active strands that use the TLB. It's an | |
1602 | // optiomisation, in cosim we don;t care about performance. | |
1603 | // | |
1604 | // When not in cosim we optimise the number of strands that receive | |
1605 | // FLUSH_TTE messages to the strands that are running. All strands | |
1606 | // that are not running don;t cache code so don't have to flush ... | |
1607 | ||
1608 | if (!sim_state.cosim()) | |
1609 | { | |
1610 | if (sgn->running) | |
1611 | { | |
1612 | inst_tlb->add_strand(this); | |
1613 | if (inst_tlb != data_tlb) | |
1614 | data_tlb->add_strand(this); | |
1615 | flush_tte_all(); | |
1616 | } | |
1617 | else | |
1618 | { | |
1619 | assert(running); | |
1620 | inst_tlb->rem_strand(this); | |
1621 | if (inst_tlb != data_tlb) | |
1622 | data_tlb->rem_strand(this); | |
1623 | } | |
1624 | } | |
1625 | ||
1626 | // When in halted mode we transition to running or parked and hence | |
1627 | // get out of halted mode. | |
1628 | ||
1629 | unhalt(sgn->running); | |
1630 | break; | |
1631 | ||
1632 | case SS_Signal::EXTERNAL_INTERRUPT: | |
1633 | if (halted) | |
1634 | unhalt(); // Force wakeup on external interrupt receive | |
1635 | (internal_interrupt)(this,sgn->irq_type,sgn->irq_raise); | |
1636 | break; | |
1637 | ||
1638 | case SS_Signal::FREE: | |
1639 | fprintf(stderr,"SS_Strand: Free signal got onto the wrong list\n"); | |
1640 | *(char*)0 = 0; | |
1641 | ||
1642 | default: | |
1643 | assert(0); | |
1644 | } | |
1645 | } | |
1646 | ||
1647 | // Now enable the next irq if any. The EXTERNAL_INTERRUPT above | |
1648 | // needs to be prevented from raising an interrupt when one is | |
1649 | // already pending. | |
1650 | ||
1651 | if (trap_type != SS_Trap::RESERVED) | |
1652 | sim_state.irq_pending(0); | |
1653 | ||
1654 | return !running; | |
1655 | } | |
1656 | /*}}}*/ | |
1657 | void SS_Strand::irq_launch( SS_Trap::Type trap_type, bool do_time_out )/*{{{*/ | |
1658 | { | |
1659 | // In cosim mode we can not throw a disrupting trap directly as it | |
1660 | // will cause a PC mismatch for sure. RTL usually tells us when it | |
1661 | // is time to take a trap. So it's here that we store the disrupting | |
1662 | // traps into an interrupt sync buffer and it there that we wait for | |
1663 | // RTL to tell us when it's time to actually launch it. | |
1664 | ||
1665 | if (irq_store) | |
1666 | { | |
1667 | sim_state.irq_pending(false); | |
1668 | (irq_store)(irq_sync,trap_type,do_time_out); | |
1669 | } | |
1670 | else | |
1671 | { | |
1672 | msg.set_handle_trap(trap_type); | |
1673 | } | |
1674 | } | |
1675 | /*}}}*/ | |
1676 | ||
1677 | SS_Vaddr SS_Strand::ss_trap( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i, SS_Trap::Type tt )/*{{{*/ | |
1678 | { | |
1679 | assert(tt); | |
1680 | assert(tt < SS_Trap::MAX_TT); | |
1681 | ||
1682 | // In case the mmu is near an inst va breakpoint and the mmu traps then we | |
1683 | // end up taking this route back to step. So we need to reset the saved | |
1684 | // decoder back to the instruction decoder. | |
1685 | ||
1686 | s->inst_dec = s->save_dec; | |
1687 | ||
1688 | // RESET_GEN_WMR & RESET_GEN_DBR are not real trap, they are similar to | |
1689 | // POR, used for warm_reset or dbx_reset, respectively | |
1690 | ||
1691 | if ((tt != SS_Trap::RESET_GEN_WMR) && (tt != SS_Trap::RESET_GEN_DBR)) | |
1692 | { | |
1693 | if ((SS_Trap::MAX_TT > tt) && (tt >= SS_Trap::TCC_INSTRUCTION_HPRV)) | |
1694 | { | |
1695 | // The code generated for the tcc instruction does not make a special case for | |
1696 | // user mode; when only 7 bits of the software trap number are valid iso 8 bits. | |
1697 | // We'll take care of that corner case here. | |
1698 | ||
1699 | if (s->sim_state.priv() == SS_Strand::SS_USER) | |
1700 | tt = SS_Trap::Type(int(tt) - 0x80); | |
1701 | } | |
1702 | else if (tt >= SS_Trap::TCC_INSTRUCTION) | |
1703 | { | |
1704 | // Legion hacks the solaris binary and inserts tcc with tt=0x175 that get called | |
1705 | // in hprv mode. They use that to shortcut some expensive bcopy I believe to speed | |
1706 | // up solaris boot on Legion. Since we don't seem to be able to build our own binary for | |
1707 | // solaris we get them from the Legion fooks and hence have to support this hack (bleh!) | |
1708 | ||
1709 | if ((s->sim_state.priv() == SS_Strand::SS_HPRV) && !s->sim_state.cosim() && (int(tt) == 0x175)) | |
1710 | { | |
1711 | s->npc = npc + 4; | |
1712 | return npc; | |
1713 | } | |
1714 | } | |
1715 | } | |
1716 | ||
1717 | // Check the breakpoints and if one or more triggered we leave ss_trap() | |
1718 | // before handling the trap. ToDo ... do we want this or do we want | |
1719 | // watchpoint or do we want both. | |
1720 | ||
1721 | if (s->break_trap[tt]) | |
1722 | { | |
1723 | bool break_out = false; | |
1724 | ||
1725 | for (SS_BreakPoint* bp = s->break_trap[tt]; bp; bp = bp->link) | |
1726 | if (bp->enabled && bp->trigger(s)) | |
1727 | break_out = true; | |
1728 | ||
1729 | if (break_out) | |
1730 | { | |
1731 | // For breakpoints on disrupting traps we have to reinject the trap | |
1732 | // into the system else it will get dropped. | |
1733 | ||
1734 | if (SS_Trap::table[tt].disrupting) | |
1735 | s->msg.set_handle_trap(tt); | |
1736 | ||
1737 | return pc; | |
1738 | } | |
1739 | } | |
1740 | ||
1741 | // Check the trace callback to see if we are tracing traps | |
1742 | ||
1743 | if (s->trc_hook) | |
1744 | s->trc_hook->trap(SS_Trap::Type(tt)); | |
1745 | ||
1746 | // Handle the trap and set the state accordingly | |
1747 | ||
1748 | if (tt == SS_Trap::POWER_ON_RESET) | |
1749 | { | |
1750 | s->trap_state.memset(0); // Clear the whole trap stack | |
1751 | ||
1752 | s->tt = tt; | |
1753 | s->tpc = 0; | |
1754 | s->tnpc = 0; | |
1755 | s->tl = s->max_tl(); | |
1756 | s->gl = s->max_gl(); | |
1757 | s->tick.npt(1); | |
1758 | s->stick.npt(1); | |
1759 | s->tick_cmpr.int_dis(1); | |
1760 | s->stick_cmpr.int_dis(1); | |
1761 | s->hstick_cmpr.int_dis(1); | |
1762 | s->fprs.fef(1); | |
1763 | s->pstate.tle(0).mm(0).pef(1).am(0).priv(1).ie(0).cle(0).tct(0); // priv(1) comes from N2 | |
1764 | s->hpstate.red(1).hpriv(1).ibe(0).tlz(0); | |
1765 | ||
1766 | pc = s->rstv_addr() + (SS_Vaddr(tt) << 5); | |
1767 | ||
1768 | s->cansave = s->max_wp() - 1; | |
1769 | s->canrestore = 0; | |
1770 | s->cleanwin = s->max_wp(); | |
1771 | s->otherwin = 0; | |
1772 | } | |
1773 | else if ((tt == SS_Trap::RESET_GEN_WMR) || (tt == SS_Trap::RESET_GEN_DBR)) | |
1774 | { | |
1775 | // wmr and dbr are triggered by reset_gen (0x89_0000_0808) | |
1776 | // RESET_GEN_WMR and RESET_GEN_DBR are not real trap type, they are used | |
1777 | // to distinguish them from POWER_ON_RESET | |
1778 | ||
1779 | tt = SS_Trap::POWER_ON_RESET; | |
1780 | ||
1781 | s->tt = tt; | |
1782 | // The PRM (Chapter 13, June 2006) is in error with respect to TPC and TNPC | |
1783 | // on warm reset. The PC and NPC registers are not protected throughout | |
1784 | // warm reset (specifically during the scan flush) so they go to 0 before | |
1785 | // the trap is taken, and therefore TPC and TNPC at MAXTL get set to 0. | |
1786 | s->tpc = 0; | |
1787 | s->tnpc = 0; | |
1788 | s->tstate.gl(s->gl()).ccr(s->ccr()).asi(s->asi()).pstate(0).cwp(s->cwp()); | |
1789 | s->htstate = 0; | |
1790 | s->tl = s->max_tl(); | |
1791 | s->gl = s->max_gl(); | |
1792 | s->tick.npt(1); | |
1793 | s->stick.npt(1); | |
1794 | s->tick_cmpr.int_dis(1); | |
1795 | s->stick_cmpr.int_dis(1); | |
1796 | s->hstick_cmpr.int_dis(1); | |
1797 | s->pstate.tle(0).mm(0).pef(1).am(0).priv(1).ie(0).cle(0).tct(0); // priv(1) comes from N2 | |
1798 | s->hpstate.red(1).hpriv(1).ibe(0).tlz(0); | |
1799 | ||
1800 | pc = s->rstv_addr() + (SS_Vaddr(tt) << 5); | |
1801 | ||
1802 | s->gl_load(); | |
1803 | } | |
1804 | else | |
1805 | { | |
1806 | s->gl_save(); | |
1807 | s->tl_save(); | |
1808 | ||
1809 | // For processors that don't implement the full 64bits of address space we | |
1810 | // don't expect to keep the full 64bit of tpc and tnpc: sign extend | |
1811 | // the tpn and tnpc on read and write to hide the upper bits. We keep the | |
1812 | // upper bits so that we can properly detect when we fall into a va-hole, | |
1813 | // regardless of whether the pstate.am bit was on for a while or not. | |
1814 | ||
1815 | s->tpc = pc & (s->mask_pstate_am | (s->mask_pstate_am << s->va_bits())); | |
1816 | s->tnpc = npc & (s->mask_pstate_am | (s->mask_pstate_am << s->va_bits())); | |
1817 | ||
1818 | s->tstate.pstate(s->pstate()).cwp(s->cwp()).asi(s->asi()).ccr(s->ccr()).gl(s->gl()); | |
1819 | s->htstate.hpstate(s->hpstate()); | |
1820 | ||
1821 | switch (tt) | |
1822 | { | |
1823 | case SS_Trap::WATCHDOG_RESET: | |
1824 | s->tt = tt; | |
1825 | break; | |
1826 | case SS_Trap::EXTERNALLY_INITIATED_RESET: | |
1827 | s->tt = tt; | |
1828 | // XIR on N2 does not go through error state | |
1829 | // when tl maxes out. On those product the xir_error_state() flag | |
1830 | // is false. Products like do circulate through the error state. | |
1831 | // So for those the bit is set. | |
1832 | if (s->sim_state.xir_error_state() && (s->tl() == s->max_tl())) | |
1833 | tt = SS_Trap::WATCHDOG_RESET; | |
1834 | break; | |
1835 | case SS_Trap::SOFTWARE_INITIATED_RESET: | |
1836 | s->tt = tt; | |
1837 | if (s->tl() == s->max_tl()) | |
1838 | tt = SS_Trap::WATCHDOG_RESET; | |
1839 | break; | |
1840 | default: | |
1841 | s->tt = tt; | |
1842 | if ((tt == SS_Trap::HSTICK_MATCH) && (s->sim_state.hintp_hsp_clear())) | |
1843 | s->hintp.hsp(0); | |
1844 | if (s->tl() == s->max_tl()) | |
1845 | tt = SS_Trap::WATCHDOG_RESET; | |
1846 | else if (s->hpstate.red() || (s->tl() == (s->max_tl() - 1))) | |
1847 | tt = SS_Trap::RED_STATE_EXCEPTION; | |
1848 | break; | |
1849 | } | |
1850 | ||
1851 | s->tl = (s->tl() == s->max_tl()) ? s->max_tl() : (s->tl() + 1); | |
1852 | s->gl = (s->gl() == s->max_gl()) ? s->max_gl() : (s->gl() + 1); | |
1853 | ||
1854 | if (tt <= SS_Trap::RED_STATE_EXCEPTION) | |
1855 | { | |
1856 | s->pstate.mm(0).pef(1).priv(1).am(0).ie(0).tct(0).cle(0).tle(0); // priv(1).tle(0) comes from N2 | |
1857 | s->hpstate.red(1).hpriv(1).ibe(0).tlz(0); | |
1858 | s->lsu_ctr = 0; // from N2 this probably has to move out ... does not have lsu_ctr. | |
1859 | s->sim_state.inst_mmu(0); | |
1860 | s->sim_state.data_mmu(0); | |
1861 | pc = s->rstv_addr() + (SS_Vaddr(tt) << 5); | |
1862 | } | |
1863 | else if (!SS_Trap::is_trap_to_priv(tt) || s->hpstate.hpriv()) | |
1864 | { | |
1865 | s->pstate.priv(0).cle(0).pef(1).am(0).ie(0).tct(0); | |
1866 | s->hpstate.red(0).hpriv(1).ibe(0); | |
1867 | pc = s->htba() + (SS_Vaddr(tt) << 5); | |
1868 | } | |
1869 | else if (s->tl() > s->max_ptl()) | |
1870 | { | |
1871 | s->pstate.priv(0).cle(0).pef(1).am(0).ie(0).tct(0); | |
1872 | s->hpstate.red(0).hpriv(1).ibe(0); | |
1873 | pc = s->htba() + (SS_Vaddr(SS_Trap::WATCHDOG_RESET) << 5); | |
1874 | } | |
1875 | else | |
1876 | { | |
1877 | s->gl = (s->gl() > s->max_pgl()) ? s->max_pgl() : s->gl(); | |
1878 | s->pstate.priv(1).cle(s->pstate.tle()).pef(1).am(0).ie(0).tct(0); | |
1879 | pc = s->tba() + ((s->tl() > 1) ? (SS_Vaddr(1) << 14) : 0) + (SS_Vaddr(tt) << 5); | |
1880 | } | |
1881 | ||
1882 | s->gl_load(); | |
1883 | } | |
1884 | ||
1885 | (s->sim_update)(s); | |
1886 | ||
1887 | if (s->tt() == SS_Trap::CLEAN_WINDOW) | |
1888 | { | |
1889 | s->cwp_save(); | |
1890 | s->cwp = (s->cwp() == s->max_wp()) ? 0 : (s->cwp() + 1); | |
1891 | s->cwp_load(); | |
1892 | } | |
1893 | else if (SS_Trap::is_spill(SS_Trap::Type(s->tt()))) | |
1894 | { | |
1895 | s->cwp_save(); | |
1896 | s->cwp = (s->cwp() + s->cansave() + 2) % (s->max_wp() + 1); | |
1897 | s->cwp_load(); | |
1898 | } | |
1899 | else if (SS_Trap::is_fill(SS_Trap::Type(s->tt()))) | |
1900 | { | |
1901 | s->cwp_save(); | |
1902 | s->cwp = s->cwp() ? (s->cwp() - 1) : s->max_wp(); | |
1903 | s->cwp_load(); | |
1904 | } | |
1905 | ||
1906 | s->pc = pc; | |
1907 | s->npc = pc + 4; | |
1908 | ||
1909 | // In trace mode we use the trap_taken flag and only in that | |
1910 | // mode does it make sense as there is a corresponding trap_taken(0). | |
1911 | ||
1912 | s->sim_state.trap_taken(1); | |
1913 | ||
1914 | return pc; | |
1915 | } | |
1916 | /*}}}*/ | |
1917 | ||
1918 | bool SS_Strand::trap_launch_ok( SS_Trap::Type _tt )/*{{{*/ | |
1919 | { | |
1920 | // For the outside world (cosim) this function returns true | |
1921 | // when a particular trap can be thrown through (s->trap)(...). | |
1922 | ||
1923 | switch (_tt) | |
1924 | { | |
1925 | case SS_Trap::POWER_ON_RESET: | |
1926 | case SS_Trap::EXTERNALLY_INITIATED_RESET: | |
1927 | // for cosim "INTP 00 00" | |
1928 | case SS_Trap::RESET_GEN_WMR: | |
1929 | return true; | |
1930 | ||
1931 | case SS_Trap::CTRL_WORD_QUEUE_INT: | |
1932 | case SS_Trap::MODULAR_ARITH_INT: | |
1933 | case SS_Trap::SW_RECOVERABLE_ERROR: | |
1934 | case SS_Trap::HSTICK_MATCH: | |
1935 | case SS_Trap::INTERRUPT_VECTOR: | |
1936 | case SS_Trap::HW_CORRECTED_ERROR: | |
1937 | return !hpstate.hpriv() || pstate.ie(); | |
1938 | ||
1939 | case SS_Trap::CPU_MONDO_TRAP: | |
1940 | case SS_Trap::DEV_MONDO_TRAP: | |
1941 | case SS_Trap::RESUMABLE_ERROR: | |
1942 | return pstate.ie() && !hpstate.hpriv(); | |
1943 | ||
1944 | case SS_Trap::INTERRUPT_LEVEL_1: | |
1945 | case SS_Trap::INTERRUPT_LEVEL_2: | |
1946 | case SS_Trap::INTERRUPT_LEVEL_3: | |
1947 | case SS_Trap::INTERRUPT_LEVEL_4: | |
1948 | case SS_Trap::INTERRUPT_LEVEL_5: | |
1949 | case SS_Trap::INTERRUPT_LEVEL_6: | |
1950 | case SS_Trap::INTERRUPT_LEVEL_7: | |
1951 | case SS_Trap::INTERRUPT_LEVEL_8: | |
1952 | case SS_Trap::INTERRUPT_LEVEL_9: | |
1953 | case SS_Trap::INTERRUPT_LEVEL_10: | |
1954 | case SS_Trap::INTERRUPT_LEVEL_11: | |
1955 | case SS_Trap::INTERRUPT_LEVEL_12: | |
1956 | case SS_Trap::INTERRUPT_LEVEL_13: | |
1957 | case SS_Trap::INTERRUPT_LEVEL_14: | |
1958 | case SS_Trap::INTERRUPT_LEVEL_15: | |
1959 | return !hpstate.hpriv() && (pil() <= (_tt - SS_Trap::INTERRUPT_LEVEL_1)); | |
1960 | ||
1961 | // I don;t expect any other traps but lets assume we can take then and complain silently | |
1962 | ||
1963 | default: | |
1964 | fprintf(stderr,"SS_Strand::trap_launch_ok called with tt=%x, update switch\n",_tt); | |
1965 | return true; | |
1966 | } | |
1967 | } | |
1968 | /*}}}*/ | |
1969 | ||
1970 | SS_AsiSpace::Error SS_Strand::scratchpad_ld64( SS_Node*, void* _reg, SS_Strand*, SS_Vaddr va, uint64_t* data )/*{{{*/ | |
1971 | { | |
1972 | assert(va < 64); | |
1973 | uint64_t* reg = (uint64_t*)_reg; | |
1974 | *data = reg[(va >> 3) & 7]; | |
1975 | return SS_AsiSpace::OK; | |
1976 | } | |
1977 | /*}}}*/ | |
1978 | SS_AsiSpace::Error SS_Strand::scratchpad_st64( SS_Node*, void* _reg, SS_Strand*, SS_Vaddr va, uint64_t data )/*{{{*/ | |
1979 | { | |
1980 | assert(va < 64); | |
1981 | uint64_t* reg = (uint64_t*)_reg; | |
1982 | reg[(va >> 3) & 7] = data; | |
1983 | return SS_AsiSpace::OK; | |
1984 | } | |
1985 | /*}}}*/ | |
1986 | ||
1987 | SS_AsiSpace::Error SS_Strand::lsu_ctr_st64( SS_Node*, void* _reg, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/ | |
1988 | { | |
1989 | SS_LsuCtr* lc = (SS_LsuCtr*)_reg; | |
1990 | (*lc) = data; | |
1991 | (s->sim_update)(s); | |
1992 | return SS_AsiSpace::OK; | |
1993 | } | |
1994 | /*}}}*/ | |
1995 | ||
1996 | inline uint64_t run_loop( SS_Strand* s, SS_Instr* opc, SS_InstrCache::Tag* tag, uint64_t n )/*{{{*/ | |
1997 | { | |
1998 | SS_InstrCache::Tag* info_ptr; | |
1999 | ||
2000 | // Preload s->inst_mmu so that compiler does not do load followed by call | |
2001 | // Keep s->signal in a local var so that compiler loads well before use | |
2002 | // Keep the instruction to execute in local variable to break load followed by call | |
2003 | ||
2004 | SS_InstMmu inst_mmu = s->inst_mmu; | |
2005 | uint64_t sgn = s->msg.is_pending(); | |
2006 | SS_Execute inst_exe; | |
2007 | ||
2008 | SS_Vaddr line_idx; | |
2009 | SS_Instr* line_ptr; | |
2010 | SS_Vaddr inst_idx; | |
2011 | SS_Instr* inst_ptr; | |
2012 | SS_Vaddr line_pc; | |
2013 | SS_Vaddr pc = s->pc(); | |
2014 | ||
2015 | // Start the most critical loop of the simulator. Every line of code | |
2016 | // here is overhead ... really. So don't add more code. Loop while we | |
2017 | // still have n instructions to execute and we don;t have to deal with | |
2018 | // an exceptional case (sgn == 0), e.g. have not received a signal. | |
2019 | ||
2020 | while (n && (sgn == 0)) | |
2021 | { | |
2022 | assert(sizeof(SS_InstrCache::Tag) == 32); // line_idx << 4 ... below | |
2023 | line_idx = ((pc >> (SS_InstrCache::LINE_BITS + 2)) & SS_InstrCache::MASK); | |
2024 | line_ptr = (SS_Instr*)((char*)opc + (line_idx << (SS_Instr::BITS + SS_InstrCache::LINE_BITS))); | |
2025 | info_ptr = (SS_InstrCache::Tag*)((char*)tag + (line_idx << 5)); // see assert above | |
2026 | line_pc = pc &~ (SS_InstrCache::LINE_MASK << 2); | |
2027 | inst_idx = (pc & (SS_InstrCache::LINE_MASK << 2)) << (SS_Instr::BITS - 2 - SS_Instr::SKEW); | |
2028 | inst_ptr = (SS_Instr*)((char*)line_ptr + inst_idx); | |
2029 | inst_exe = inst_ptr->exe; | |
2030 | ||
2031 | #if !defined(ARCH_X64) | |
2032 | // Look ahead and prefetch the L2 ... this makes as perform better | |
2033 | // on busy machines. | |
2034 | ||
2035 | ss_prefetch((char*)inst_ptr + 1024); | |
2036 | #endif | |
2037 | ||
2038 | // Check line tte and tag: the instruction cache is smaller then the | |
2039 | // largest page size. If either of them mismatches then call the mmu | |
2040 | // to do an tlb lookup. The current instuction tte is set to the fail_tte | |
2041 | // in case a trap occured in the mmu; bail out as we most certainly | |
2042 | // will have to handle a reenterloop signal due to trap handling. | |
2043 | ||
2044 | if ((info_ptr->tte != s->inst_tte) || (info_ptr->tag != line_pc)) | |
2045 | { | |
2046 | pc = (inst_mmu)(pc,s->npc(),s,line_ptr,info_ptr); | |
2047 | ||
2048 | // In case we hit a breakpoint in inst_mmu then we will not execute the | |
2049 | // while loop, but we will account n wrongly by 1 after that, fix it. | |
2050 | // Note sgn != 0 when a breakpoint is hit. Also when inst_tte == fail_tte | |
2051 | // then we will exit here below, so correct by 1 there too. | |
2052 | ||
2053 | if (s->inst_tte == s->fail_tte) | |
2054 | { | |
2055 | s->pc = pc; | |
2056 | return s->break_hit ? n : (n - 1); | |
2057 | } | |
2058 | ||
2059 | inst_exe = inst_ptr->exe; | |
2060 | sgn = s->msg.is_pending(); | |
2061 | ||
2062 | if (s->break_hit) | |
2063 | n--; | |
2064 | } | |
2065 | ||
2066 | // Now execute the instructions in the cache line, until the loop count | |
2067 | // (n) becomes zero, or the pc falls of the line, or we have to | |
2068 | // deal with a signal due to priviledge mode switches, breakpoints, etc. | |
2069 | ||
2070 | while (n && ((pc &~ (SS_InstrCache::LINE_MASK << 2)) == line_pc) && (sgn == 0)) | |
2071 | { | |
2072 | pc = (inst_exe)(pc,s->npc(),s,inst_ptr); | |
2073 | ||
2074 | inst_idx = (pc & (SS_InstrCache::LINE_MASK << 2)) << (SS_Instr::BITS - 2 - SS_Instr::SKEW); | |
2075 | inst_ptr = (SS_Instr*)((char*)line_ptr + inst_idx); | |
2076 | inst_exe = inst_ptr->exe; | |
2077 | sgn = s->msg.is_pending(); | |
2078 | ||
2079 | n--; | |
2080 | } | |
2081 | ||
2082 | // Breakpoints can be hit during inst_exe. This means that we | |
2083 | // have to break out and not execute the instruction. The code | |
2084 | // above does one n-- too many in case of a breakpoint hit, fix that. | |
2085 | ||
2086 | if (s->break_hit) | |
2087 | n++; | |
2088 | } | |
2089 | s->pc = pc; | |
2090 | return n; | |
2091 | } | |
2092 | /*}}}*/ | |
2093 | inline uint64_t trc_loop( SS_Strand* s, SS_Instr* opc, SS_InstrCache::Tag* tag, uint64_t n )/*{{{*/ | |
2094 | { | |
2095 | assert(n == 1); // Assert the obvious, execute one instruction, output trace for it if we executed, etc. | |
2096 | ||
2097 | // @@ha144505, for now this code is a copy of the run_loop ... bad style | |
2098 | // but I have to fix a tracing bug first. We'll clean this up later. | |
2099 | ||
2100 | SS_InstrCache::Tag* info_ptr; | |
2101 | ||
2102 | // Preload s->inst_mmu so that compiler does not do load followed by call | |
2103 | // Keep s->signal in a local var so that compiler loads well before use | |
2104 | // Keep the instruction to execute in local variable to break load followed by call | |
2105 | ||
2106 | SS_InstMmu inst_mmu = s->inst_mmu; | |
2107 | bool sgn = s->msg.is_pending(); | |
2108 | SS_Execute inst_exe; | |
2109 | ||
2110 | SS_Vaddr line_idx; | |
2111 | SS_Instr* line_ptr; | |
2112 | SS_Vaddr inst_idx; | |
2113 | SS_Instr* inst_ptr; | |
2114 | SS_Vaddr line_pc; | |
2115 | SS_Vaddr pc = s->pc(); | |
2116 | ||
2117 | // Start the most critical loop of the simulator. Every line of code | |
2118 | // here is overhead ... really. So don't add more code. Loop while we | |
2119 | // still have n instructions to execute and we don;t have to deal with | |
2120 | // an exceptional case (sgn == 0), e.g. have not received a signal. | |
2121 | ||
2122 | if (sgn == 0) | |
2123 | { | |
2124 | assert(sizeof(SS_InstrCache::Tag) == 32); // line_idx << 4 ... below | |
2125 | line_idx = ((pc >> (SS_InstrCache::LINE_BITS + 2)) & SS_InstrCache::MASK); | |
2126 | line_ptr = (SS_Instr*)((char*)opc + (line_idx << (SS_Instr::BITS + SS_InstrCache::LINE_BITS))); | |
2127 | info_ptr = (SS_InstrCache::Tag*)((char*)tag + (line_idx << 5)); // see assert above | |
2128 | line_pc = pc &~ (SS_InstrCache::LINE_MASK << 2); | |
2129 | inst_idx = (pc & (SS_InstrCache::LINE_MASK << 2)) << (SS_Instr::BITS - 2 - SS_Instr::SKEW); | |
2130 | inst_ptr = (SS_Instr*)((char*)line_ptr + inst_idx); | |
2131 | inst_exe = inst_ptr->exe; | |
2132 | ||
2133 | #if !defined(ARCH_X64) | |
2134 | // Look ahead and prefetch the L2 ... this makes as perform better | |
2135 | // on busy machines. | |
2136 | ||
2137 | ss_prefetch((char*)inst_ptr + 1024); | |
2138 | #endif | |
2139 | ||
2140 | // Check line tte and tag: the instruction cache is smaller then the | |
2141 | // largest page size. If either of them mismatches then call the mmu | |
2142 | // to do an tlb lookup. The current instuction tte is set to the fail_tte | |
2143 | // in case a trap occured in the mmu; bail out as we most certainly | |
2144 | // will have to handle a reenterloop signal due to trap handling. | |
2145 | ||
2146 | // Decode cache and RAS I$ cache flushing are now decoupled somewhat to | |
2147 | // reduce the cost of instruction decoding. | |
2148 | // The I$ is now a subset of the decode cache. If a line is cast out of | |
2149 | // the I$, the corresponding decode tte entry is marked RAS_TTE_POISON | |
2150 | // (which just sets the least significant bit), while preserving the tte | |
2151 | // and its decode cache entry. | |
2152 | ||
2153 | // The predicate is that: | |
2154 | ||
2155 | // 1) Every decode cache entry without RAS_TTE_POISON is in I$ cache. | |
2156 | // 2) Every decode cache entry *with* RAS_TTE_POISON corresponds to an | |
2157 | // I$ line that has a RAS error or has been flushed from the I$. | |
2158 | ||
2159 | if (info_ptr->tte_bits & SS_Strand::RAS_TTE_POISON) | |
2160 | { | |
2161 | assert(s->sim_state.ras_enabled()); | |
2162 | info_ptr->tte_bits &= ~SS_Strand::RAS_TTE_POISON; | |
2163 | ||
2164 | if ((info_ptr->tte == s->inst_tte) && (info_ptr->tag == line_pc)) | |
2165 | { | |
2166 | SS_Paddr pa = s->inst_tte->trans(line_pc); | |
2167 | SS_Trap::Type trap_type = | |
2168 | s->mem_err_detector.detect_fetch_err(SS_MemErrDetector::L1_CACHE_AND_STB, | |
2169 | pc, s->npc(), s, pa); | |
2170 | ||
2171 | if (trap_type != SS_Trap::NO_TRAP) | |
2172 | { | |
2173 | pc = (s->trap)(pc,s->npc(),s,line_ptr,trap_type); | |
2174 | s->inst_tte = s->fail_tte; | |
2175 | info_ptr->tte_bits |= SS_Strand::RAS_TTE_POISON; | |
2176 | goto mmu_ras_trap; | |
2177 | } | |
2178 | } | |
2179 | } | |
2180 | ||
2181 | if ((info_ptr->tte != s->inst_tte) || (info_ptr->tag != line_pc)) | |
2182 | { | |
2183 | pc = (inst_mmu)(pc,s->npc(),s,line_ptr,info_ptr); | |
2184 | ||
2185 | if (s->inst_tte == s->fail_tte) | |
2186 | { | |
2187 | mmu_ras_trap: | |
2188 | ||
2189 | s->pc = pc; | |
2190 | ||
2191 | if (s->break_hit) | |
2192 | return n; | |
2193 | ||
2194 | // ToDo: The if cosim below is to make regression pass. The tte used | |
2195 | // for tracing is whatever was used last for tracing. This is not correct | |
2196 | // but it makes the regession pas to get this bug fix out. | |
2197 | // We should rerun all the cosims with this if taken out and the | |
2198 | // tte set to zero. The trace should report a non number for the pa and | |
2199 | // opcode field, say dashes. | |
2200 | ||
2201 | if (!s->sim_state.cosim()) | |
2202 | s->trc_inst_tte = s->inst_tte; | |
2203 | ||
2204 | // return 0 means trace instruction, hence lock the tte for reuse | |
2205 | // as we need it. After outputting the trace the tte is given up. | |
2206 | ||
2207 | if (s->trc_hook) | |
2208 | s->inst_tlb->lock_reuse_tte(s->trc_inst_tte); | |
2209 | ||
2210 | return 0; | |
2211 | } | |
2212 | ||
2213 | inst_exe = inst_ptr->exe; | |
2214 | sgn = s->msg.is_pending(); | |
2215 | } | |
2216 | ||
2217 | if (sgn == 0) | |
2218 | { | |
2219 | // In tracing mode we need to hold on to the TTE until we have traced | |
2220 | // the instruction ... we do this because demap could invalidate the TTE | |
2221 | // in the decode cache of the very instruction we are tracing. | |
2222 | ||
2223 | s->trc_inst_tte = s->inst_tte; | |
2224 | if (s->trc_hook) | |
2225 | s->inst_tlb->lock_reuse_tte(s->trc_inst_tte); | |
2226 | ||
2227 | // Now execute the instructions in the cache line, until the loop count | |
2228 | // (n) becomes zero, or the pc falls of the line, or we have to | |
2229 | // deal with a signal due to priviledge mode switches, breakpoints, etc. | |
2230 | ||
2231 | pc = (inst_exe)(pc,s->npc(),s,inst_ptr); | |
2232 | ||
2233 | inst_idx = (pc & (SS_InstrCache::LINE_MASK << 2)) << (SS_Instr::BITS - 2 - SS_Instr::SKEW); | |
2234 | inst_ptr = (SS_Instr*)((char*)line_ptr + inst_idx); | |
2235 | inst_exe = inst_ptr->exe; | |
2236 | sgn = s->msg.is_pending(); | |
2237 | ||
2238 | // Breakpoints can be hit during inst_exe. This means that we | |
2239 | // have to break out and not execute the instruction. The code | |
2240 | // above does one n-- too many in case of a breakpoint hit, fix that. | |
2241 | ||
2242 | if (!s->break_hit) | |
2243 | n = 0; | |
2244 | } | |
2245 | } | |
2246 | ||
2247 | s->pc = pc; | |
2248 | return n; | |
2249 | } | |
2250 | /*}}}*/ | |
2251 | ||
2252 | void SS_Strand::run_tick( uint64_t incr )/*{{{*/ | |
2253 | // | |
2254 | // run_tick() updates the (s)tick value and compares it | |
2255 | // against the tick_cmpr, stick_cmp and hstick_cmpr | |
2256 | // and raises traps if tick matches occur. | |
2257 | // | |
2258 | // In cosim mode we don't change the softint stick and tick | |
2259 | // match bits (sm and tm) ourselves: rtl doesn't trust our | |
2260 | // our administration of time ... and rightfully so. | |
2261 | // | |
2262 | // In other simulation modes the tick and stick value can | |
2263 | // increase by more then 1 between steps, so compare for >= | |
2264 | // i.s.o. the exact match. Additionally to prevent multiple | |
2265 | // interrupts we only check the interrupt when the sm or | |
2266 | // tm bits are getting set (rising edge). | |
2267 | { | |
2268 | uint64_t t = stick.counter() + incr; | |
2269 | ||
2270 | tick.counter(t); | |
2271 | stick.counter(t); | |
2272 | ||
2273 | bool err_found = false; | |
2274 | if (sim_state.ras_enabled()) | |
2275 | { | |
2276 | if(mem_err_detector.tick_err_detector) | |
2277 | { | |
2278 | err_found = mem_err_detector.tick_err_detector(this); | |
2279 | } | |
2280 | } | |
2281 | ||
2282 | // Check tick against hstick_cmpr, stick_cmpr and | |
2283 | // tck_cmpr in that order. The order is important for | |
2284 | // trap prioprity reasons. | |
2285 | ||
2286 | // The comparison operation is suppressed, if an error is detected in any of | |
2287 | // tick compare registers | |
2288 | ||
2289 | if (!err_found) | |
2290 | { | |
2291 | if (t >= hstick_cmpr()) | |
2292 | { | |
2293 | if (sim_state.cosim()) | |
2294 | { | |
2295 | // just drop them, follow me ?? | |
2296 | } | |
2297 | else if (hintp.hsp() == 0) | |
2298 | { | |
2299 | if (halted) | |
2300 | unhalt(); // Force wakeup in case the irq is blocked | |
2301 | hintp.hsp(1); | |
2302 | irq.raise(this,SS_Interrupt::BIT_HSTICK_MATCH); | |
2303 | } | |
2304 | } | |
2305 | ||
2306 | if (t >= stick_cmpr()) | |
2307 | { | |
2308 | if (sim_state.cosim()) | |
2309 | { | |
2310 | irq.check(this); | |
2311 | } | |
2312 | else if (softint.sm() == 0) | |
2313 | { | |
2314 | if (halted) | |
2315 | unhalt(); // Force wakeup in case the irq is blocked | |
2316 | softint.sm(1); | |
2317 | irq.update_softint(this); | |
2318 | } | |
2319 | } | |
2320 | ||
2321 | if (t >= tick_cmpr()) | |
2322 | { | |
2323 | if (sim_state.cosim()) | |
2324 | { | |
2325 | irq.check(this); | |
2326 | } | |
2327 | else if (softint.tm() == 0) | |
2328 | { | |
2329 | if (halted) | |
2330 | unhalt(); // Forece wakeup in case the irq is blocked | |
2331 | softint.tm(1); | |
2332 | irq.update_softint(this); | |
2333 | } | |
2334 | } | |
2335 | } | |
2336 | ||
2337 | } | |
2338 | /*}}}*/ | |
2339 | ||
2340 | uint64_t SS_Strand::run_step( uint64_t count )/*{{{*/ | |
2341 | { | |
2342 | uint64_t save_count = count; | |
2343 | running = sim_state.running(); | |
2344 | ||
2345 | break_hit = 0; | |
2346 | ||
2347 | // If step is called and we're not in running mode, and we | |
2348 | // have some signal in the queue that requires us to leave | |
2349 | // step (breakpoint) then we exit .. and return the number of | |
2350 | // instructions executed .... which in case we got out of | |
2351 | // running mode is 0 and in case of a breakpoint is count. | |
2352 | ||
2353 | if ((running == 0) && peek_signal()) | |
2354 | return running ? count : 0; | |
2355 | ||
2356 | while (running && count) | |
2357 | { | |
2358 | if (peek_signal()) | |
2359 | { | |
2360 | inst_count = inst_count() + save_count - count; | |
2361 | return running ? count : 0; | |
2362 | } | |
2363 | ||
2364 | count = run_loop(this,inst_cache->opc,inst_cache->tag,count); | |
2365 | } | |
2366 | ||
2367 | inst_count = inst_count() + save_count - count; | |
2368 | ||
2369 | sim_state.running(running); | |
2370 | return 0; | |
2371 | } | |
2372 | /*}}}*/ | |
2373 | uint64_t SS_Strand::trc_step( uint64_t count )/*{{{*/ | |
2374 | { | |
2375 | uint64_t save_count = count; | |
2376 | running = sim_state.running(); | |
2377 | ||
2378 | break_hit = 0; | |
2379 | ||
2380 | if (running == 0 && peek_signal()) | |
2381 | return running ? count : 0; | |
2382 | ||
2383 | while (running && count) | |
2384 | { | |
2385 | if (peek_signal()) | |
2386 | { | |
2387 | inst_count = inst_count() + save_count - count; | |
2388 | return running ? count : 0; | |
2389 | } | |
2390 | ||
2391 | SS_InstrCache* trc_cache = inst_cache; | |
2392 | SS_Vaddr trc_pc = pc(); | |
2393 | ||
2394 | // Now step one instruction in trace mode ... | |
2395 | ||
2396 | if (!trc_loop(this,inst_cache->opc,inst_cache->tag,1)) | |
2397 | { | |
2398 | count -= 1; | |
2399 | ||
2400 | if (trc_hook) | |
2401 | { | |
2402 | SS_Registers::Index i; | |
2403 | ||
2404 | uint_t sft = 64 - va_bits(); | |
2405 | ||
2406 | trc_hook->exe_instr((trc_pc << sft) >> sft,trc_inst_tte,trc_cache->pc_inst(trc_pc)); | |
2407 | ||
2408 | trc_hook->cmp_state(SS_Registers::ASR_PC,pc()); | |
2409 | trc_hook->cmp_state(SS_Registers::SIM_NPC,npc()); | |
2410 | ||
2411 | for (i=SS_Registers::IRF_OFS; i < SS_Registers::IRF_END; i = i+1) | |
2412 | trc_hook->cmp_state(i,irf[i - SS_Registers::IRF_OFS]); | |
2413 | for (i=SS_Registers::DRF_OFS; i < SS_Registers::DRF_END; i = i+1) | |
2414 | trc_hook->cmp_state(i,drf[i - SS_Registers::DRF_OFS]); | |
2415 | ||
2416 | trc_hook->cmp_state(SS_Registers::ASR_Y,y()); | |
2417 | trc_hook->cmp_state(SS_Registers::ASR_CCR,ccr()); | |
2418 | trc_hook->cmp_state(SS_Registers::ASR_ASI,asi()); | |
2419 | trc_hook->cmp_state(SS_Registers::ASR_FPRS,fprs()); | |
2420 | trc_hook->cmp_state(SS_Registers::ASR_GSR,gsr()); | |
2421 | trc_hook->cmp_state(SS_Registers::SIM_FSR,fsr()); | |
2422 | trc_hook->cmp_state(SS_Registers::PR_PSTATE,pstate()); | |
2423 | trc_hook->cmp_state(SS_Registers::HPR_HPSTATE,hpstate()); | |
2424 | trc_hook->cmp_state(SS_Registers::PR_GL,gl()); | |
2425 | trc_hook->cmp_state(SS_Registers::PR_TBA,tba()); | |
2426 | trc_hook->cmp_state(SS_Registers::HPR_HTBA,htba()); | |
2427 | trc_hook->cmp_state(SS_Registers::PR_TL,tl()); | |
2428 | trc_hook->cmp_state(SS_Registers::PR_TT,tt()); | |
2429 | trc_hook->cmp_state(SS_Registers::PR_TPC,SS_Vaddr(tpc() << (64 - va_bits())) >> (64 - va_bits())); | |
2430 | trc_hook->cmp_state(SS_Registers::PR_TNPC,SS_Vaddr(tnpc() << (64 - va_bits())) >> (64 - va_bits())); | |
2431 | trc_hook->cmp_state(SS_Registers::PR_TSTATE,tstate()); | |
2432 | trc_hook->cmp_state(SS_Registers::HPR_HTSTATE,htstate()); | |
2433 | trc_hook->cmp_state(SS_Registers::PR_CWP,cwp()); | |
2434 | trc_hook->cmp_state(SS_Registers::PR_CANSAVE,cansave()); | |
2435 | trc_hook->cmp_state(SS_Registers::PR_CANRESTORE,canrestore()); | |
2436 | trc_hook->cmp_state(SS_Registers::PR_CLEANWIN,cleanwin()); | |
2437 | trc_hook->cmp_state(SS_Registers::PR_OTHERWIN,otherwin()); | |
2438 | trc_hook->cmp_state(SS_Registers::ASR_TICK_CMPR,tick_cmpr()); | |
2439 | trc_hook->cmp_state(SS_Registers::ASR_STICK_CMPR,stick_cmpr()); | |
2440 | trc_hook->cmp_state(SS_Registers::HPR_HSTICK_CMPR,hstick_cmpr()); | |
2441 | trc_hook->cmp_state(SS_Registers::HPR_HINTP,hintp()); | |
2442 | trc_hook->cmp_state(SS_Registers::PR_PIL,pil()); | |
2443 | trc_hook->cmp_state(SS_Registers::ASR_SOFTINT,softint()); | |
2444 | ||
2445 | trc_hook->end_instr(); | |
2446 | ||
2447 | // Now release the trc_tte as we are not using it any longer. | |
2448 | ||
2449 | inst_tlb->reuse_tte(trc_inst_tte); | |
2450 | } | |
2451 | ||
2452 | if(mem_err_detector.step_hook) | |
2453 | { | |
2454 | //traps taken here have priorities that don't follow the trap priority hierarchy | |
2455 | SS_Trap::Type trap_type = mem_err_detector.step_hook(this); | |
2456 | if(trap_type != SS_Trap::NO_TRAP) | |
2457 | { | |
2458 | (trap)(pc(),npc(),this,0,trap_type); | |
2459 | } | |
2460 | } | |
2461 | } | |
2462 | } | |
2463 | ||
2464 | inst_count = inst_count() + save_count - count; | |
2465 | ||
2466 | sim_state.running(running); | |
2467 | return 0; | |
2468 | } | |
2469 | /*}}}*/ | |
2470 | ||
2471 | void SS_Strand::add_tracer( SS_Tracer* trc )/*{{{*/ | |
2472 | { | |
2473 | assert(trc); | |
2474 | ||
2475 | trc->next = trc_hook; | |
2476 | trc_hook = trc; | |
2477 | if (trc_hook->need_mem_trc() && !sim_state.ras_enabled()) | |
2478 | mem_table = mem_trc_table_ref; | |
2479 | } | |
2480 | /*}}}*/ | |
2481 | void SS_Strand::del_tracer( SS_Tracer* trc )/*{{{*/ | |
2482 | { | |
2483 | assert(trc); | |
2484 | ||
2485 | if (trc_hook) | |
2486 | { | |
2487 | if (trc_hook == trc) | |
2488 | { | |
2489 | trc_hook = trc_hook->next; | |
2490 | trc->next = 0; | |
2491 | trc = 0; | |
2492 | } | |
2493 | else | |
2494 | { | |
2495 | SS_Tracer* head = trc_hook; | |
2496 | for (SS_Tracer* next = trc_hook->next; trc && next; head = next, next = next->next) | |
2497 | { | |
2498 | if (next == trc) | |
2499 | { | |
2500 | head->next = next->next; | |
2501 | trc = 0; | |
2502 | } | |
2503 | } | |
2504 | } | |
2505 | } | |
2506 | ||
2507 | if (((trc_hook == 0) || !trc_hook->need_mem_trc()) && !sim_state.ras_enabled()) | |
2508 | mem_table = mem_run_table_ref; | |
2509 | ||
2510 | if (trc) | |
2511 | fprintf(stderr,"ERROR: SS_Tracer: There is no tracer connected\n"); | |
2512 | } | |
2513 | /*}}}*/ | |
2514 | ||
2515 | static inline SS_Instr* line_index( SS_Instr* line, uint_t n )/*{{{*/ | |
2516 | { | |
2517 | return (SS_Instr*)((char*)line + (n << (SS_Instr::BITS - SS_Instr::SKEW))); | |
2518 | } | |
2519 | /*}}}*/ | |
2520 | ||
2521 | SS_Vaddr mem_run_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte )/*{{{*/ | |
2522 | { | |
2523 | SS_Paddr pa = tte->trans(va); | |
2524 | #if defined(MEMORY_MSYNC) | |
2525 | ((SS_MsyncMemory*)(s->memory))->msync_info(s->strand_id(),va); | |
2526 | #elif defined(MEMORY_EXTERNAL) | |
2527 | ((SS_ExternalMemory*)(s->memory))->set_strand_id(s->strand_id()); | |
2528 | #endif | |
2529 | ((SS_Memory*)(s->memory))->SS_Memory::fetch512(pa,s->mem_data); | |
2530 | ||
2531 | uint64_t d0 = s->mem_data[0]; | |
2532 | uint64_t d1 = s->mem_data[1]; | |
2533 | uint64_t d2 = s->mem_data[2]; | |
2534 | uint64_t d3 = s->mem_data[3]; | |
2535 | uint64_t d4 = s->mem_data[4]; | |
2536 | uint64_t d5 = s->mem_data[5]; | |
2537 | uint64_t d6 = s->mem_data[6]; | |
2538 | uint64_t d7 = s->mem_data[7]; | |
2539 | ||
2540 | line->line_index(0)->opc = d0 >> 32; | |
2541 | line->line_index(1)->opc = d0; | |
2542 | line->line_index(2)->opc = d1 >> 32; | |
2543 | line->line_index(3)->opc = d1; | |
2544 | line->line_index(4)->opc = d2 >> 32; | |
2545 | line->line_index(5)->opc = d2; | |
2546 | line->line_index(6)->opc = d3 >> 32; | |
2547 | line->line_index(7)->opc = d3; | |
2548 | line->line_index(8)->opc = d4 >> 32; | |
2549 | line->line_index(9)->opc = d4; | |
2550 | line->line_index(10)->opc = d5 >> 32; | |
2551 | line->line_index(11)->opc = d5; | |
2552 | line->line_index(12)->opc = d6 >> 32; | |
2553 | line->line_index(13)->opc = d6; | |
2554 | line->line_index(14)->opc = d7 >> 32; | |
2555 | line->line_index(15)->opc = d7; | |
2556 | ||
2557 | SS_Execute dec = s->inst_dec; | |
2558 | ||
2559 | line->line_index(0)->exe = dec; | |
2560 | line->line_index(1)->exe = dec; | |
2561 | line->line_index(2)->exe = dec; | |
2562 | line->line_index(3)->exe = dec; | |
2563 | line->line_index(4)->exe = dec; | |
2564 | line->line_index(5)->exe = dec; | |
2565 | line->line_index(6)->exe = dec; | |
2566 | line->line_index(7)->exe = dec; | |
2567 | line->line_index(8)->exe = dec; | |
2568 | line->line_index(9)->exe = dec; | |
2569 | line->line_index(10)->exe = dec; | |
2570 | line->line_index(11)->exe = dec; | |
2571 | line->line_index(12)->exe = dec; | |
2572 | line->line_index(13)->exe = dec; | |
2573 | line->line_index(14)->exe = dec; | |
2574 | line->line_index(15)->exe = dec; | |
2575 | ||
2576 | // Reset the decoder back to the normal decoder. In some cases | |
2577 | // (inst va breakpoint) the inst_mmu can set the decoder to a | |
2578 | // special decoder that is for just one cache line | |
2579 | ||
2580 | s->inst_dec = s->save_dec; | |
2581 | ||
2582 | return pc; | |
2583 | } | |
2584 | /*}}}*/ | |
2585 | SS_Vaddr io_run_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte )/*{{{*/ | |
2586 | { | |
2587 | SS_Paddr pa = tte->trans(va); | |
2588 | s->io->fetch512(s->strand_id(),pa,s->mem_data); | |
2589 | ||
2590 | uint64_t d0 = s->mem_data[0]; | |
2591 | uint64_t d1 = s->mem_data[1]; | |
2592 | uint64_t d2 = s->mem_data[2]; | |
2593 | uint64_t d3 = s->mem_data[3]; | |
2594 | uint64_t d4 = s->mem_data[4]; | |
2595 | uint64_t d5 = s->mem_data[5]; | |
2596 | uint64_t d6 = s->mem_data[6]; | |
2597 | uint64_t d7 = s->mem_data[7]; | |
2598 | ||
2599 | line_index(line,0)->opc = d0 >> 32; | |
2600 | line_index(line,1)->opc = d0; | |
2601 | line_index(line,2)->opc = d1 >> 32; | |
2602 | line_index(line,3)->opc = d1; | |
2603 | line_index(line,4)->opc = d2 >> 32; | |
2604 | line_index(line,5)->opc = d2; | |
2605 | line_index(line,6)->opc = d3 >> 32; | |
2606 | line_index(line,7)->opc = d3; | |
2607 | line_index(line,8)->opc = d4 >> 32; | |
2608 | line_index(line,9)->opc = d4; | |
2609 | line_index(line,10)->opc = d5 >> 32; | |
2610 | line_index(line,11)->opc = d5; | |
2611 | line_index(line,12)->opc = d6 >> 32; | |
2612 | line_index(line,13)->opc = d6; | |
2613 | line_index(line,14)->opc = d7 >> 32; | |
2614 | line_index(line,15)->opc = d7; | |
2615 | ||
2616 | SS_Execute dec = s->inst_dec; | |
2617 | ||
2618 | line_index(line,0)->exe = dec; | |
2619 | line_index(line,1)->exe = dec; | |
2620 | line_index(line,2)->exe = dec; | |
2621 | line_index(line,3)->exe = dec; | |
2622 | line_index(line,4)->exe = dec; | |
2623 | line_index(line,5)->exe = dec; | |
2624 | line_index(line,6)->exe = dec; | |
2625 | line_index(line,7)->exe = dec; | |
2626 | line_index(line,8)->exe = dec; | |
2627 | line_index(line,9)->exe = dec; | |
2628 | line_index(line,10)->exe = dec; | |
2629 | line_index(line,11)->exe = dec; | |
2630 | line_index(line,12)->exe = dec; | |
2631 | line_index(line,13)->exe = dec; | |
2632 | line_index(line,14)->exe = dec; | |
2633 | line_index(line,15)->exe = dec; | |
2634 | ||
2635 | // Reset the decoder back to the normal decoder. In some cases | |
2636 | // (inst va breakpoint) the inst_mmu can set the decoder to a | |
2637 | // special decoder that is for just one cache line | |
2638 | ||
2639 | s->inst_dec = s->save_dec; | |
2640 | ||
2641 | return pc; | |
2642 | } | |
2643 | /*}}}*/ | |
2644 | SS_Vaddr mem_trc_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte )/*{{{*/ | |
2645 | { | |
2646 | SS_Paddr pa = tte->trans(va); | |
2647 | ||
2648 | if (s->sim_state.ras_enabled()) | |
2649 | { | |
2650 | SS_Trap::Type trap_type = | |
2651 | s->mem_err_detector.detect_fetch_err(SS_MemErrDetector::L1_CACHE_AND_STB, | |
2652 | pc, npc, s, pa); | |
2653 | if (trap_type != SS_Trap::NO_TRAP) | |
2654 | return (s->trap)(pc,npc,s,line,trap_type); | |
2655 | } | |
2656 | ||
2657 | #if defined(MEMORY_MSYNC) | |
2658 | ((SS_MsyncMemory*)(s->memory))->msync_info(s->strand_id(),va); | |
2659 | #elif defined(MEMORY_EXTERNAL) | |
2660 | ((SS_ExternalMemory*)(s->memory))->set_strand_id(s->strand_id()); | |
2661 | #endif | |
2662 | s->memory->fetch512(pa,s->mem_data); | |
2663 | ||
2664 | uint64_t d0 = s->mem_data[0]; | |
2665 | uint64_t d1 = s->mem_data[1]; | |
2666 | uint64_t d2 = s->mem_data[2]; | |
2667 | uint64_t d3 = s->mem_data[3]; | |
2668 | uint64_t d4 = s->mem_data[4]; | |
2669 | uint64_t d5 = s->mem_data[5]; | |
2670 | uint64_t d6 = s->mem_data[6]; | |
2671 | uint64_t d7 = s->mem_data[7]; | |
2672 | ||
2673 | if(s->trc_hook) | |
2674 | s->trc_hook->mem_access(SS_Tracer::LD_CODE,va,tte,64,s->mem_data); | |
2675 | ||
2676 | line_index(line,0)->opc = d0 >> 32; | |
2677 | line_index(line,1)->opc = d0; | |
2678 | line_index(line,2)->opc = d1 >> 32; | |
2679 | line_index(line,3)->opc = d1; | |
2680 | line_index(line,4)->opc = d2 >> 32; | |
2681 | line_index(line,5)->opc = d2; | |
2682 | line_index(line,6)->opc = d3 >> 32; | |
2683 | line_index(line,7)->opc = d3; | |
2684 | line_index(line,8)->opc = d4 >> 32; | |
2685 | line_index(line,9)->opc = d4; | |
2686 | line_index(line,10)->opc = d5 >> 32; | |
2687 | line_index(line,11)->opc = d5; | |
2688 | line_index(line,12)->opc = d6 >> 32; | |
2689 | line_index(line,13)->opc = d6; | |
2690 | line_index(line,14)->opc = d7 >> 32; | |
2691 | line_index(line,15)->opc = d7; | |
2692 | ||
2693 | SS_Execute dec = s->inst_dec; | |
2694 | ||
2695 | line_index(line,0)->exe = dec; | |
2696 | line_index(line,1)->exe = dec; | |
2697 | line_index(line,2)->exe = dec; | |
2698 | line_index(line,3)->exe = dec; | |
2699 | line_index(line,4)->exe = dec; | |
2700 | line_index(line,5)->exe = dec; | |
2701 | line_index(line,6)->exe = dec; | |
2702 | line_index(line,7)->exe = dec; | |
2703 | line_index(line,8)->exe = dec; | |
2704 | line_index(line,9)->exe = dec; | |
2705 | line_index(line,10)->exe = dec; | |
2706 | line_index(line,11)->exe = dec; | |
2707 | line_index(line,12)->exe = dec; | |
2708 | line_index(line,13)->exe = dec; | |
2709 | line_index(line,14)->exe = dec; | |
2710 | line_index(line,15)->exe = dec; | |
2711 | ||
2712 | // Reset the decoder back to the normal decoder. In some cases | |
2713 | // (inst va breakpoint) the inst_mmu can set the decoder to a | |
2714 | // special decoder that is for just one cache line | |
2715 | ||
2716 | s->inst_dec = s->save_dec; | |
2717 | ||
2718 | return pc; | |
2719 | } | |
2720 | /*}}}*/ | |
2721 | SS_Vaddr io_trc_fetch512( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* line, SS_Vaddr va, SS_Tte* tte )/*{{{*/ | |
2722 | { | |
2723 | SS_Paddr pa = tte->trans(va); | |
2724 | ||
2725 | s->io->fetch512(s->strand_id(),pa,s->mem_data); | |
2726 | ||
2727 | if(s->trc_hook) | |
2728 | s->trc_hook->mem_access(SS_Tracer::LD_CODE,va,tte,64,s->mem_data); | |
2729 | ||
2730 | uint64_t d0 = s->mem_data[0]; | |
2731 | uint64_t d1 = s->mem_data[1]; | |
2732 | uint64_t d2 = s->mem_data[2]; | |
2733 | uint64_t d3 = s->mem_data[3]; | |
2734 | uint64_t d4 = s->mem_data[4]; | |
2735 | uint64_t d5 = s->mem_data[5]; | |
2736 | uint64_t d6 = s->mem_data[6]; | |
2737 | uint64_t d7 = s->mem_data[7]; | |
2738 | ||
2739 | line_index(line,0)->opc = d0 >> 32; | |
2740 | line_index(line,1)->opc = d0; | |
2741 | line_index(line,2)->opc = d1 >> 32; | |
2742 | line_index(line,3)->opc = d1; | |
2743 | line_index(line,4)->opc = d2 >> 32; | |
2744 | line_index(line,5)->opc = d2; | |
2745 | line_index(line,6)->opc = d3 >> 32; | |
2746 | line_index(line,7)->opc = d3; | |
2747 | line_index(line,8)->opc = d4 >> 32; | |
2748 | line_index(line,9)->opc = d4; | |
2749 | line_index(line,10)->opc = d5 >> 32; | |
2750 | line_index(line,11)->opc = d5; | |
2751 | line_index(line,12)->opc = d6 >> 32; | |
2752 | line_index(line,13)->opc = d6; | |
2753 | line_index(line,14)->opc = d7 >> 32; | |
2754 | line_index(line,15)->opc = d7; | |
2755 | ||
2756 | SS_Execute dec = s->inst_dec; | |
2757 | ||
2758 | line_index(line,0)->exe = dec; | |
2759 | line_index(line,1)->exe = dec; | |
2760 | line_index(line,2)->exe = dec; | |
2761 | line_index(line,3)->exe = dec; | |
2762 | line_index(line,4)->exe = dec; | |
2763 | line_index(line,5)->exe = dec; | |
2764 | line_index(line,6)->exe = dec; | |
2765 | line_index(line,7)->exe = dec; | |
2766 | line_index(line,8)->exe = dec; | |
2767 | line_index(line,9)->exe = dec; | |
2768 | line_index(line,10)->exe = dec; | |
2769 | line_index(line,11)->exe = dec; | |
2770 | line_index(line,12)->exe = dec; | |
2771 | line_index(line,13)->exe = dec; | |
2772 | line_index(line,14)->exe = dec; | |
2773 | line_index(line,15)->exe = dec; | |
2774 | ||
2775 | // Reset the decoder back to the normal decoder. In some cases | |
2776 | // (inst va breakpoint) the inst_mmu can set the decoder to a | |
2777 | // special decoder that is for just one cache line | |
2778 | ||
2779 | s->inst_dec = s->save_dec; | |
2780 | ||
2781 | return pc; | |
2782 | } | |
2783 | /*}}}*/ | |
2784 | ||
2785 | SS_AsiSpace::Error SS_Strand::asi_ext_ld64( SS_Node* a, void* b, SS_Strand* s, SS_Vaddr va, uint64_t* data )/*{{{*/ | |
2786 | { | |
2787 | #ifdef COMPILE_FOR_SAM | |
2788 | return (*s->asi_ext_ld64_fp)(a,b,s,va,data); | |
2789 | #else | |
2790 | return SS_AsiSpace::OK; | |
2791 | #endif | |
2792 | } | |
2793 | /*}}}*/ | |
2794 | SS_AsiSpace::Error SS_Strand::asi_ext_st64( SS_Node* a, void* b, SS_Strand* s, SS_Vaddr va, uint64_t data )/*{{{*/ | |
2795 | { | |
2796 | #ifdef COMPILE_FOR_SAM | |
2797 | return (*s->asi_ext_st64_fp)(a,b,s,va,data); | |
2798 | #else | |
2799 | return SS_AsiSpace::OK; | |
2800 | #endif | |
2801 | } | |
2802 | /*}}}*/ | |
2803 | ||
2804 | void SS_Strand::default_ras_enable(SS_Strand* s, char*)/*{{{*/ | |
2805 | { | |
2806 | fprintf(stderr,"RAS Un-implemented\n"); | |
2807 | } | |
2808 | /*}}}*/ | |
2809 | ||
2810 | /*static*/ void SS_Strand::ss_run_perf( SS_Strand* s, Sam::Vcpu::perfcntr which, | |
2811 | int64_t incr )/*{{{*/ | |
2812 | { | |
2813 | static int warned = 0; | |
2814 | if (!warned) { | |
2815 | fprintf (stderr, "Performance Instrumentation Counters " | |
2816 | "not yet implemented for this CPU\n"); | |
2817 | warned = 1; | |
2818 | } | |
2819 | } | |
2820 | /*}}}*/ |