• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1AArch64 Simulator state trace
2=============================
3
4The AArch64 Simulator can be configured to produce traces of instruction
5execution, register contents, and memory accesses. The trace is designed to be
6intuitive for human readers, but this document describes the format of the
7trace, so that post-processing tools can confidently parse the output.
8
9In VIXL's own test runner, the trace is controlled by the `--trace*` options.
10Run `test-runner --help` for details.
11
12Basic structure
13---------------
14
15Executed instructions show the address, the encoding of the instruction and the
16disassembly (as produced by VIXL's Disassembler). For example:
17
18    0x00007fbe2a6a9044  d299d200		mov x0, #0xce90
19
20The first field is the address of the instruction, with exactly 16 hexadecimal
21characters and a leading 0x, and is followed by two spaces. The second field is
22the instruction encoding, with exactly eight hexadecimal characters (and no
23leading 0x). This is followed by two _tab_ characters, and the instruction
24disassembly. The following regular expression can be used to capture each field:
25
26    (0x[0-9a-f]{16})  ([0-9a-f]{8})\t\t(.*)
27
28Following each instruction are zero or more lines of state update. Most notably,
29these represent the register state updates and memory accesses that occurred
30during simulation of the instruction. All of these lines begin with a '#'
31character, so that they can be easily identified, and filtered if necessary. For
32example:
33
34    0x00007fd2221c907c  8b82200e		add x14, x0, x2, asr #8
35    #            x14: 0xfffedcba98765432
36    0x00007fd2221c9080  0b81200f		add w15, w0, w1, asr #8
37    #            w15:         0xff89abcd
38
39Note that the Simulator uses these state update lines to describe its initial
40state. As a result, there will be state trace output before the first simulated
41instruction, and parsers need to be tolerant of this.
42
43Note that padding white space is used liberally to keep values vertically
44aligned throughout the trace (as shown with the write to `w15` in the example
45above). Similarly, some compound values are split into parts using the C++14
46literal separator (`'`) character. Refer to the "Memory accesses" section
47(below) for examples.
48
49Ordering
50--------
51
52VIXL guarantees that each instruction is printed before its associated state
53trace.
54
55State trace must be interpreted sequentially, line by line. VIXL avoids updating
56the same register more than once (because it makes the trace hard for humans to
57read), but this can occur in some situations, and should be supported by
58parsers.
59
60The state is intended to be consistent with architectural execution at the start
61of each instruction and at the end of the whole trace, but no such guarantees
62are made about the traced state _between_ instructions. VIXL prioritises
63human-readability when choosing the ordering of state updates.
64
65If simulated registers are modified externally, for example using
66`WriteRegister` from C++ code, their state will (by default) be logged
67immediately. In the full trace, it will appear as though the (runtime) call or
68return instruction modified the state. This is consistent with the guarantees
69above, but it can result in single instructions appearing to generate a large
70number of state updates.
71
72There is no upper limit on the number of state update lines that any one
73instruction can generate.
74
75Whole register trace
76--------------------
77
78The simplest form of state trace has the form "`REG: VALUE`", meaning that
79the register `REG` has the specified value, and any high-order bits in aliased
80registers are set to zero.
81
82    0x00007fd2221c907c  8b82200e		add x14, x0, x2, asr #8
83    #            x14: 0xfffedcba98765432
84
85Note that to correctly track state, parsers need to be aware of architectural
86register aliasing rules. Also, VIXL uses some standard register aliases, such as
87`lr` (`x30`). To avoid misinterpreting a register alias (and thereby potentially
88missing an aliased register update), some tools may need to treat an
89unrecognised register name as an error.
90
91This trace format attempts to represent _architectural_ register writes.
92However, this is not strictly checked or enforced.
93
94`VALUE` is always shown in hexadecimal (raw bits) form, with a leading `0x` and
95enough digits to exactly fill `REG`. `VALUE` may also include annotations (for
96example to show FP arithmetic values) in parentheses. These annotations are for
97the benefit of human readers, and parsers may ignore them.
98
99Note that SVE registers _always_ use the partial register trace format,
100described below, so a plain `z` or `p` register will never be used in a whole
101register trace. This is true even if the vector length is configured to 16
102bytes.
103
104Partial register trace
105----------------------
106
107Sometimes, VIXL needs to show _part_ of a register without implying that the
108rest of the register is zeroed. A partial register value is indicated by a bit
109range in angled brackets after the register name: "`REG<MSB:LSB>: VALUE`".
110This format is used for stores, for example.
111
112SVE register updates are split across multiple lines, and therefore always use
113the partial register trace format. For example (with a 384-bit VL):
114
115    0x00007fb1978da044  04214000		index z0.b, #0, #1
116    #   z0<383:256>: 0x2f2e2d2c2b2a29282726252423222120
117    #   z0<255:128>: 0x1f1e1d1c1b1a19181716151413121110
118    #     z0<127:0>: 0x0f0e0d0c0b0a09080706050403020100
119
120Note that VIXL will omit whole lines where they are unnecessary, for example if
121they have no active (predicated) lanes. Parsers should not assume that every
122part of a register will appear in such cases.
123
124The `VALUE` has the same format as in the whole register trace, except in the
125case of SVE `p` registers (as described below).
126
127SVE `p` registers
128-----------------
129
130For `p` registers, we try to keep the lanes vertically aligned with the
131corresponding parts of the `z` registers that they affect. To do this, we use a
132binary format, with a leading `0b`, and spaces between each digit. For example:
133
134    0x00007f66e539b0b8  04f54607		index z7.d, x16, #-11
135    #     z7<127:0>: 0x00000000000000150000000000000020
136    0x00007f66e539b0bc  25d8e3a7		ptrue p7.d, all
137    #      p7<15:0>: 0b 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1
138
139Memory accesses
140---------------
141
142The pattern for a memory access is "`VALUE OP ADDRESS`", where:
143
144- `VALUE` is a hexadecimal value, with visual separators (') between
145  structure components,
146- `OP` is `"->"` for a store, or `"<-"` for a load,
147- `ADDRESS` is the (hexadecimal) address of the access.
148
149Accesses shown in this style are always contiguous, and with little-endian
150semantics. However, a given instruction might have multiple lines of memory
151access trace, particularly if the instruction performs non-contiguous accesses.
152
153In the case of simple accesses, the `VALUE` is shared with register value trace:
154
155    0x00007f3835372058  e400e401		st1b { z1.b }, p1, [x0]
156    #      z1<127:0>: 0xd4d7dadde0e3e6e9eceff2f5f8fbfe01 -> 0x000055d170298e90
157
158Sign-extending loads show the whole resulting register value, with the (smaller)
159access represented on a separate line. This makes the (differing) values in the
160register and in memory unambiguous, without parsers needing to understand the
161instruction set:
162
163    0x00007f47922d0068  79800306		ldrsh x6, [x24]
164    #             x6: 0xffffffffffff8080
165    #                                  ╙─ 0x8080 <- 0x00007fffbc197708
166
167Some instructions access several different memory locations. In these cases,
168each access is given its own line, with the highest lane index first so that
169(for contiguous accesses) the lowest address ends up at the bottom:
170
171    0x00007fa6001e9060  e4217c0a		st2b { z10.b, z11.b }, p7, [x0, x1]
172    #     z10<127:0>: 0x0f0e0d0c0b0a09080706050403020100
173    #     z11<127:0>: 0x1f1e1d1c1b1a19181716151413121110
174    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙─ 0x10'00 -> 0x00007ffe485d2f90
175    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙─── 0x11'01 -> 0x00007ffe485d2f92
176    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙───── 0x12'02 -> 0x00007ffe485d2f94
177    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙─────── 0x13'03 -> 0x00007ffe485d2f96
178    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙───────── 0x14'04 -> 0x00007ffe485d2f98
179    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙─────────── 0x15'05 -> 0x00007ffe485d2f9a
180    #                    ║ ║ ║ ║ ║ ║ ║ ║ ║ ╙───────────── 0x16'06 -> 0x00007ffe485d2f9c
181    #                    ║ ║ ║ ║ ║ ║ ║ ║ ╙─────────────── 0x17'07 -> 0x00007ffe485d2f9e
182    #                    ║ ║ ║ ║ ║ ║ ║ ╙───────────────── 0x18'08 -> 0x00007ffe485d2fa0
183    #                    ║ ║ ║ ║ ║ ║ ╙─────────────────── 0x19'09 -> 0x00007ffe485d2fa2
184    #                    ║ ║ ║ ║ ║ ╙───────────────────── 0x1a'0a -> 0x00007ffe485d2fa4
185    #                    ║ ║ ║ ║ ╙─────────────────────── 0x1b'0b -> 0x00007ffe485d2fa6
186    #                    ║ ║ ║ ╙───────────────────────── 0x1c'0c -> 0x00007ffe485d2fa8
187    #                    ║ ║ ╙─────────────────────────── 0x1d'0d -> 0x00007ffe485d2faa
188    #                    ║ ╙───────────────────────────── 0x1e'0e -> 0x00007ffe485d2fac
189    #                    ╙─────────────────────────────── 0x1f'0f -> 0x00007ffe485d2fae
190
191The line-drawing characters are encoded as UTF-8 (as is this document). There is
192currently no locale handling in VIXL, so this is not configurable. However,
193since these annotations are for the benefit of human readers, parsers can safely
194ignore them, and treat the whole trace as an ASCII byte stream (ignoring 8-bit
195characters). This is useful in situations where UTF-8 handling carries an
196unacceptable performance cost.
197
198In the future, VIXL may offer an option to avoid printing these annotations, so
199that the trace is restricted to single-byte characters.
200
201Floating-point value annotations
202--------------------------------
203
204Some floating-point operations produce register trace that annotates the raw
205values with the corresponding FP arithmetic values. This is for the benefit of
206human readers (and has limited precision). Such annotations follow the `VALUE`
207in parentheses.
208
209Scalar form:
210
211    #             s1:                         0x3f800000 (1.000) <- 0x00007ffdc64d2314
212
213Vector form, updating all S lanes using a load:
214
215    #            v16: 0x1211100f0e0d0c0b0a09080706050403 (4.577e-28, 1.739e-30, 6.598e-33, 2.502e-35)
216    #                          ║       ║       ║       ╙─ 0x06050403 <- 0x00007ffe56fd7863
217    #                          ║       ║       ╙───────── 0x0a090807 <- 0x00007ffe56fd7867
218    #                          ║       ╙───────────────── 0x0e0d0c0b <- 0x00007ffe56fd786b
219    #                          ╙───────────────────────── 0x1211100f <- 0x00007ffe56fd786f
220
221Vector form, updating a single S lane using a load:
222
223    #             v2: 0x03020100040302017ff0f0027f80f000 (..., 1.540e-36, ...)
224    #                                  ╙───────────────── 0x04030201 <- 0x00007ffc7b2e3ca1
225
226Vector form, replicating a single struct load to all S lanes:
227
228    #            v15: 0x100f0e0d100f0e0d100f0e0d100f0e0d (2.821e-29, 2.821e-29, 2.821e-29, 2.821e-29)
229    #            v16: 0x14131211141312111413121114131211 (7.425e-27, 7.425e-27, 7.425e-27, 7.425e-27)
230    #            v17: 0x18171615181716151817161518171615 (1.953e-24, 1.953e-24, 1.953e-24, 1.953e-24)
231    #                          ╙───────╨───────╨───────╨─ 0x18171615'14131211'100f0e0d <- 0x00007ffdd64d847d
232