Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: SS_Tracer.h | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | ||
24 | #ifndef __SS_Tracer_h__ | |
25 | #define __SS_Tracer_h__ | |
26 | ||
27 | #include <string.h> | |
28 | #include "SS_Registers.h" | |
29 | #include "SS_Types.h" | |
30 | #include "SS_Trap.h" | |
31 | #include "SS_Instr.h" | |
32 | ||
33 | class SS_Tte; | |
34 | class SS_Tlb; | |
35 | ||
36 | class SS_Tracer | |
37 | { | |
38 | public: | |
39 | enum TrapMode | |
40 | { | |
41 | NO_TRAP, | |
42 | TRAP, | |
43 | INST_TRAP, | |
44 | DATA_TRAP | |
45 | }; | |
46 | ||
47 | enum MemAccess | |
48 | { | |
49 | LD_CODE = 0x01, | |
50 | ST_DATA = 0x02, | |
51 | LD_DATA = 0x03, | |
52 | ST_PART = 0x04, // data[0] = rd, data[1] = bytemask | |
53 | ST_SWAP = 0x05, // data[0] = rd | |
54 | LD_SWAP = 0x07, // data[0] = rd | |
55 | ST_CAS = 0x08, // data[0] = rd, data[1] = rs2 | |
56 | LD_CAS = 0x09, // data[0] = rd | |
57 | ST_LDST = 0x0a, // data[0] = store value (ldstub stores 0xff) | |
58 | LD_LDST = 0x0b, // data[0] = rd | |
59 | FLUSH = 0x10, // data == 0 in mem_access call | |
60 | PREFETCH = 0x11 // data == 0 in mem_access call | |
61 | }; | |
62 | ||
63 | static int is_fetch( MemAccess ma ) { return ma == LD_CODE; } | |
64 | static int is_load( MemAccess ma ) { return (ma & 1) == 1; } | |
65 | static int is_store( MemAccess ma ) { return (ma & 1) == 0; } | |
66 | static int is_cohere( MemAccess ma ) { return (ma & 0x10) == 0x10; } | |
67 | ||
68 | ||
69 | SS_Tracer() | |
70 | : | |
71 | hook_exe_instr(0), | |
72 | hook_reg_value(0), | |
73 | hook_trap(0), | |
74 | hook_mem_access(0), | |
75 | hook_asi_access(0), | |
76 | hook_tlb_update(0), | |
77 | hook_hwop(0), | |
78 | hook_end_instr(0), | |
79 | trap_mode(NO_TRAP), | |
80 | trap_addr(0), | |
81 | next(0) | |
82 | { | |
83 | memset(state,0,sizeof(state)); | |
84 | } | |
85 | virtual ~SS_Tracer() {} | |
86 | ||
87 | void (*hook_exe_instr) ( SS_Tracer*, SS_Vaddr pc, SS_Tte* tte, SS_Instr* i ); | |
88 | void (*hook_reg_value) ( SS_Tracer*, SS_Registers::Index index, uint64_t value ); | |
89 | void (*hook_trap) ( SS_Tracer*, SS_Trap::Type tt, TrapMode mode, SS_Vaddr ea ); | |
90 | void (*hook_mem_access)( SS_Tracer*, MemAccess, SS_Vaddr, SS_Tte*, uint_t size, uint64_t* data ); | |
91 | void (*hook_asi_access)( SS_Tracer*, MemAccess, uint8_t asi, SS_Vaddr, uint64_t* data ); | |
92 | void (*hook_tlb_update)( SS_Tracer*, bool insert, SS_Tlb* tlb, uint_t index, SS_Tte* tte ); | |
93 | void (*hook_hwop) ( SS_Tracer*, MemAccess type, SS_Paddr addr, uint_t size, uint64_t *value ); | |
94 | void (*hook_end_instr) ( SS_Tracer* ); | |
95 | ||
96 | SS_Tracer* next; // There can be more then one tracer per strand | |
97 | ||
98 | bool need_mem_trc() | |
99 | { | |
100 | if (hook_mem_access) | |
101 | return true; | |
102 | else if (next) | |
103 | return next->need_mem_trc(); | |
104 | else | |
105 | return false; | |
106 | } | |
107 | ||
108 | // exe_instr() is called for every instruction to trace its | |
109 | // virtual pc, physical pc and the instruction word executed. | |
110 | void exe_instr( SS_Vaddr pc, SS_Tte* tte, SS_Instr* i ) | |
111 | { | |
112 | if (hook_exe_instr) (hook_exe_instr)(this,pc,tte,i); | |
113 | if (next) next->exe_instr(pc,tte,i); | |
114 | } | |
115 | ||
116 | // reg_value() is called for each register that changed value as a | |
117 | // result of executing an instruction. Note that this is a template | |
118 | // function to allow for product spefic SS_Registers::Index extensions. | |
119 | // The given index is casted to SS_Register::Index. | |
120 | template<class Index> | |
121 | void reg_value( Index index, uint64_t value ) | |
122 | { | |
123 | if (hook_reg_value) (hook_reg_value)(this,SS_Registers::Index(index),value); | |
124 | if (next) next->reg_value(SS_Registers::Index(index),value); | |
125 | } | |
126 | ||
127 | // trap() is called to trace trapping | |
128 | void trap( SS_Trap::Type trap_type ) | |
129 | { | |
130 | // in cosim mode, there are likely two (or more) SS_Tracer objects are | |
131 | // registered (i.e., linked by 'next' field) for each strand. When a trap | |
132 | // occurres, we have to traverse through all of them to perform each | |
133 | // object's own trace function. If a trap is a mmu trap, then an | |
134 | // inst_trap() or data_trap() will be called before the trap() is called, | |
135 | // since inst_trap() and data_trap() may deposit more specific | |
136 | // trap_mode and trap_addr information, we should not overwrite those | |
137 | // fields in such case. | |
138 | if (trap_mode == NO_TRAP) | |
139 | { | |
140 | trap_mode = TRAP; | |
141 | trap_addr = 0; | |
142 | } | |
143 | if (hook_trap) (hook_trap)(this,trap_type,trap_mode,trap_addr); | |
144 | if (next) next->trap(trap_type); | |
145 | } | |
146 | ||
147 | // mem_access() is called before memory is written and/or after | |
148 | // memory is read. Note atomic instruction do both read and write. | |
149 | void mem_access( MemAccess type, SS_Vaddr va, SS_Tte* tte, uint_t size, uint64_t* data ) | |
150 | { | |
151 | if (hook_mem_access) (hook_mem_access)(this,type,va,tte,size,data); | |
152 | if (next) next->mem_access(type,va,tte,size,data); | |
153 | } | |
154 | ||
155 | // asi_access is called after non translating asi is read/written | |
156 | void asi_access( MemAccess type, uint8_t asi, SS_Vaddr va, uint64_t* data ) | |
157 | { | |
158 | if (hook_asi_access) (hook_asi_access)(this,type,asi,va,data); | |
159 | if (next) next->asi_access(type,asi,va,data); | |
160 | } | |
161 | ||
162 | ||
163 | // tlb_update() is called whenever a tte is inserted or removed from the | |
164 | // tlb. The tte can not be cached. All values need need to be read in | |
165 | // during the call tlb_update() call. | |
166 | void tlb_update( bool insert, SS_Tlb* tlb, uint_t index, SS_Tte* tte ) | |
167 | { | |
168 | if (hook_tlb_update) (hook_tlb_update)(this,insert,tlb,index,tte); | |
169 | if (next) next->tlb_update(insert,tlb,index,tte); | |
170 | } | |
171 | ||
172 | // hwop() is called whenever a hw state machine access memory to | |
173 | // to fetch tte from tsb. | |
174 | void hwop( MemAccess type, SS_Paddr addr, uint_t size, uint64_t *value ) | |
175 | { | |
176 | if (hook_hwop) (hook_hwop)(this,type, addr, size, value); | |
177 | if (next) next->hwop(type, addr, size, value); | |
178 | } | |
179 | ||
180 | ||
181 | ||
182 | // end_instr() is called when all the above tracing interface calls | |
183 | // have been made. Its can be used to for example the output trace record | |
184 | // for an instruction. | |
185 | void end_instr() | |
186 | { | |
187 | if (hook_end_instr) (hook_end_instr)(this); | |
188 | if (next) next->end_instr(); | |
189 | } | |
190 | ||
191 | void inst_trap( SS_Vaddr ea ) | |
192 | { | |
193 | trap_mode = INST_TRAP; | |
194 | trap_addr = ea; | |
195 | if (next) next->inst_trap(ea); | |
196 | } | |
197 | void data_trap( SS_Vaddr ea ) | |
198 | { | |
199 | trap_mode = DATA_TRAP; | |
200 | trap_addr = ea; | |
201 | if (next) next->data_trap(ea); | |
202 | } | |
203 | ||
204 | void cmp_state( SS_Registers::Index i, uint64_t v ) | |
205 | { | |
206 | if (state[i] != v) | |
207 | { | |
208 | reg_value(i,v); | |
209 | state[i] = v; | |
210 | } | |
211 | if (next) next->cmp_state(i,v); | |
212 | } | |
213 | ||
214 | TrapMode get_trap_mode() { return trap_mode; } | |
215 | ||
216 | // ToDo: This state vector should really not be here. | |
217 | uint64_t state[SS_Registers::INDEX_END - SS_Registers::INDEX_BEGIN]; | |
218 | ||
219 | protected: | |
220 | TrapMode trap_mode; | |
221 | SS_Vaddr trap_addr; | |
222 | }; | |
223 | ||
224 | #endif |