| # OTBN Tracer |
| |
| The tracer consists of a module (`otbn_tracer.sv`) and an interface |
| (`otbn_trace_if.sv`). The interface is responsible for directly probing the |
| design and implementing any basic tracking logic that is required. The module |
| takes an instance of this interface and uses it to produce trace data. |
| |
| Trace output is provided to the simulation environment by calling the |
| `accept_otbn_trace_string` function which is imported via DPI (the simulator |
| environment provides its implementation). Each call to |
| `accept_otbn_trace_string` provides a trace record and a cycle count. There is |
| at most one call per cycle. Further details are below. |
| |
| A typical setup would bind an instantiation of `otbn_trace_if` and |
| `otbn_tracer` into `otbn_core` passing the `otbn_trace_if` instance into the |
| `otbn_tracer` instance. However this is no need for `otbn_tracer` to be bound |
| into `otbn_core` provided it is given a `otbn_trace_if` instance. |
| |
| ## Trace Format |
| |
| Trace output is generated as a series of records. Every record has zero or more |
| *header lines*, followed by zero or more *body lines*. There is no fixed |
| ordering within the header lines or the body lines. |
| |
| The type of any line can be identified by its first character. The possible |
| types for header lines are as follows: |
| |
| - `S`: **Instruction stall**. An instruction is stalled. |
| - `E`: **Instruction execute**. An instruction completed its execution. |
| - `U`: **Wipe in progress**. OTBN is in the middle of an internal wipe. |
| - `V`: **Wipe complete**. An internal wipe has completed. |
| |
| The possible types for body lines are: |
| |
| - `<`: **Register read**: A register has been read. |
| - `>`: **Register write**: A register has been written. |
| - `R`: **Memory load**: A value has been loaded from memory. |
| - `W`: **Memory store**: A value has been stored to memory. |
| |
| See the [sections below](#line-formats) for details of what information is in |
| the different lines. |
| |
| A well-formed record has exactly one header line, but it's possible for the |
| tracer to generate other records if something goes wrong in the design. It is |
| not the tracer's responsibility to detect bugs; the simulation environment |
| should flag these as errors in a suitable way. |
| |
| An instruction execution will be represented by zero or more `S` records, |
| followed by one `E` record that represents the retirement of the instruction. |
| The secure wipe phase at the end of OTBN's operation will be represented by |
| zero or more `U` records, followed by a final `V` record. |
| |
| Whilst the tracer does not aim to detect bugs, there may be instances where the |
| signals it traces do something unexpected that requires special behaviour. |
| Where this happens, the string `"ERR"` will be placed somewhere in the line |
| that contains information about the unexpected signals. See information on |
| Memory Write (`W`) lines below for an example. `ERR` will not be present in |
| trace output for any other reason. |
| |
| ### Record examples |
| (The first line of each example illustrates the instruction being traced to aid the example and |
| is not part of the record) |
| |
| Executing `BN.SID x26++, 0(x25)` at PC 0x00000158: |
| ``` |
| E PC: 0x00000158, insn: 0x01acd08b |
| < w20: 0x78fccc06_2228e9d6_89c9b54f_887cf14e_c79af825_69be57d4_fecd21a1_b9dd0141 |
| < x25: 0x00000020 |
| < x26: 0x00000014 |
| > x26: 0x00000015 |
| W [0x00000020]: 0x78fccc06_2228e9d6_89c9b54f_887cf14e_c79af825_69be57d4_fecd21a1_b9dd0141 |
| ``` |
| |
| Executing `BN.ADD w3, w1, w2` at PC 0x000000e8: |
| ``` |
| E PC: 0x000000e8, insn: 0x002081ab |
| < w01: 0x78fccc06_2228e9d6_89c9b54f_887cf14e_c79af825_69be586e_9866bb3b_53769ada |
| < w02: 0x99999999_99999999_99999999_99999999_99999999_99999999_99999999_99999999 |
| > w03: 0x1296659f_bbc28370_23634ee9_22168ae8_613491bf_0357f208_320054d4_ed103473 |
| > FLAGS0: {C: 1, M: 0, L: 1, Z: 0} |
| ``` |
| |
| ## Line formats |
| |
| ### Instruction Execute (`E`) and Stall (`S`) lines |
| |
| These indicate that an instruction is executing or stalling. An 'E' line |
| indicates the instruction completed in the trace record's cycle. An instruction |
| that is stalled will first produce a record containing an 'S' line and will |
| produce a matching 'E' line in a future record on the cycle it unstalls and |
| finishes. The line provides the PC and raw instruction bits. |
| |
| Instruction at 0x0000014c is 0x01800d13 and stalling (a future record will |
| contain a matching 'E' line): |
| ``` |
| S PC: 0x0000014c, insn: 0x01800d13 |
| ``` |
| |
| Instruction at 0x00000150 is 0x01acc10b is executing and will complete: |
| ``` |
| E PC: 0x00000150, insn: 0x01acc10b |
| ``` |
| |
| ### Secure wipe (`U` and `V`) lines |
| |
| These indicate that a secure wipe operation is in progress. There is no other |
| information, so the line consists of a bare `U` or `V` character. |
| |
| ### Register Read (`<`) and Write (`>`) lines |
| |
| These show data that has been read or written to either register files or |
| special purpose registers (such as ACC or the bignum side flags). The line |
| provides the register name and the data read/written |
| |
| Register x26 was read and contained value 0x00000018: |
| ``` |
| < x26: 0x00000018 |
| ``` |
| |
| Register w24 had value |
| `0xcccccccc_bbbbbbbb_aaaaaaaa_facefeed_deadbeef_cafed00d_d0beb533_1234abcd` |
| written to it: |
| ``` |
| > w24: 0xcccccccc_bbbbbbbb_aaaaaaaa_facefeed_deadbeef_cafed00d_d0beb533_1234abcd |
| ``` |
| |
| Accumulator had value |
| `0x00000000_00000000_00311bcb_5e157313_a2fd5453_c7eb58ce_1a1d070d_673963ce` |
| written to it: |
| ``` |
| > ACC: 0x00000000_00000000_00311bcb_5e157313_a2fd5453_c7eb58ce_1a1d070d_673963ce |
| ``` |
| |
| Flag group 0 had value `{C: 1, M: 1, L: 1, Z: 0}` written to it: |
| ``` |
| > FLAGS0: {C: 1, M: 1, L: 1, Z: 0} |
| ``` |
| |
| ### Memory Read (`R`) and Write (`W`) lines |
| |
| These indicate activity on the Dmem bus. The line provides the address and data |
| written/read. For a read the data is always WLEN bits and the address is WLEN |
| aligned (for an execution of LW only a 32-bit chunk of that data is required). |
| For a write the write mask is examined. Where the mask indicates a bignum side |
| write (BN.SID) full WLEN bit data is provided and the address is WLEN aligned. |
| Where the mask indicates a base side write (SW) only 32-bit data is provided and |
| the address is 32-bit aligned (giving the full address of the written chunk). |
| |
| Address `0x00000040` was read and contained value |
| `0xcccccccc_bbbbbbbb_aaaaaaaa_facefeed_deadbeef_cafed00d_baadf00d_1234abcd`: |
| ``` |
| R [0x00000040]: 0xcccccccc_bbbbbbbb_aaaaaaaa_facefeed_deadbeef_cafed00d_baadf00d_1234abcd |
| ``` |
| |
| Address `0x00000004` had value `0xd0beb533` written to it: |
| ``` |
| W [0x00000004]: 0xd0beb533 |
| ``` |
| |
| In the event of an OTBN bug that produces bad memory masks on writes (where the |
| write is neither to a full 256 bits nor a aligned 32-bit chunk), an error line |
| is produced giving the full mask and data |
| ``` |
| W [0x00000080]: Mask ERR Mask: 0xfffff800_0000ffff_ffffffff_00000000_00000000_00000000_00000000_00000000 Data: 0xcccccccc_bbbbbbbb_aaaaaaaa_facefeed_deadbeef_cafed00d_baadf00d_1234abcd |
| ``` |
| |
| ## Using with dvsim |
| |
| To use this code, depend on the core file. If you're using dvsim, |
| you'll also need to include `otbn_tracer_sim_opts.hjson` in your |
| simulator configuration and add `"{tool}_otbn_tracer_build_opts"` to |
| the `en_build_modes` variable. |