lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | """ |
| 5 | Generates the documentation for the register tool |
| 6 | |
| 7 | """ |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 8 | from .access import SWACCESS_PERMITTED, HWACCESS_PERMITTED |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 9 | from reggen import (validate, |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 10 | ip_block, enum_entry, field, |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 11 | register, multi_register, window) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 12 | |
| 13 | |
| 14 | def genout(outfile, msg): |
| 15 | outfile.write(msg) |
| 16 | |
| 17 | |
| 18 | doc_intro = """ |
| 19 | |
Rupert Swarbrick | 1104203 | 2020-11-25 10:32:04 +0000 | [diff] [blame] | 20 | <!-- Start of output generated by `regtool.py --doc` --> |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 21 | |
| 22 | The tables describe each key and the type of the value. The following |
| 23 | types are used: |
| 24 | |
| 25 | Type | Description |
| 26 | ---- | ----------- |
| 27 | """ |
| 28 | |
| 29 | swaccess_intro = """ |
| 30 | |
| 31 | Register fields are tagged using the swaccess key to describe the |
| 32 | permitted access and side-effects. This key must have one of these |
| 33 | values: |
| 34 | |
| 35 | """ |
| 36 | |
| 37 | hwaccess_intro = """ |
| 38 | |
| 39 | Register fields are tagged using the hwaccess key to describe the |
| 40 | permitted access from hardware logic and side-effects. This key must |
| 41 | have one of these values: |
| 42 | |
| 43 | """ |
| 44 | |
| 45 | top_example = """ |
| 46 | The basic structure of a register definition file is thus: |
| 47 | |
| 48 | ```hjson |
| 49 | { |
| 50 | name: "GP", |
| 51 | regwidth: "32", |
| 52 | registers: [ |
| 53 | // register definitions... |
| 54 | ] |
| 55 | } |
| 56 | |
| 57 | ``` |
| 58 | |
| 59 | """ |
| 60 | |
| 61 | register_example = """ |
| 62 | |
| 63 | The basic register definition group will follow this pattern: |
| 64 | |
| 65 | ```hjson |
| 66 | { name: "REGA", |
| 67 | desc: "Description of register", |
| 68 | swaccess: "rw", |
| 69 | resval: "42", |
| 70 | fields: [ |
| 71 | // bit field definitions... |
| 72 | ] |
| 73 | } |
| 74 | ``` |
| 75 | |
| 76 | The name and brief description are required. If the swaccess key is |
| 77 | provided it describes the access pattern that will be used by all |
| 78 | bitfields in the register that do not override with their own swaccess |
| 79 | key. This is a useful shortcut because in most cases a register will |
| 80 | have the same access restrictions for all fields. The reset value of |
| 81 | the register may also be provided here or in the individual fields. If |
| 82 | it is provided in both places then they must match, if it is provided |
| 83 | in neither place then the reset value defaults to zero for all except |
| 84 | write-only fields when it defaults to x. |
| 85 | |
| 86 | """ |
| 87 | |
| 88 | field_example = """ |
| 89 | |
| 90 | Field names should be relatively short because they will be used |
| 91 | frequently (and need to fit in the register layout picture!) The field |
| 92 | description is expected to be longer and will most likely make use of |
Philipp Wagner | 14a3fee | 2019-11-21 10:07:02 +0000 | [diff] [blame] | 93 | the Hjson ability to include multi-line strings. An example with three |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 94 | fields: |
| 95 | |
| 96 | ```hjson |
| 97 | fields: [ |
| 98 | { bits: "15:0", |
| 99 | name: "RXS", |
| 100 | desc: ''' |
| 101 | Last 16 oversampled values of RX. These are captured at 16x the baud |
| 102 | rate clock. This is a shift register with the most recent bit in |
| 103 | bit 0 and the oldest in bit 15. Only valid when ENRXS is set. |
| 104 | ''' |
| 105 | } |
| 106 | { bits: "16", |
| 107 | name: "ENRXS", |
| 108 | desc: ''' |
| 109 | If this bit is set the receive oversampled data is collected |
| 110 | in the RXS field. |
| 111 | ''' |
| 112 | } |
| 113 | {bits: "20:19", name: "TXILVL", |
| 114 | desc: "Trigger level for TX interrupts", |
| 115 | resval: "2", |
| 116 | enum: [ |
| 117 | { value: "0", name: "txlvl1", desc: "1 character" }, |
| 118 | { value: "1", name: "txlvl4", desc: "4 characters" }, |
| 119 | { value: "2", name: "txlvl8", desc: "8 characters" }, |
| 120 | { value: "3", name: "txlvl16", desc: "16 characters" } |
| 121 | ] |
| 122 | } |
| 123 | ] |
| 124 | ``` |
| 125 | |
| 126 | In all of these the swaccess parameter is inherited from the register |
| 127 | level, and will be added so this key is always available to the |
| 128 | backend. The RXS and ENRXS will default to zero reset value (unless |
| 129 | something different is provided for the register) and will have the |
| 130 | key added, but TXILVL expicitly sets its reset value as 2. |
| 131 | |
| 132 | The missing bits 17 and 18 will be treated as reserved by the tool, as |
| 133 | will any bits between 21 and the maximum in the register. |
| 134 | |
| 135 | The TXILVL is an example using an enumeration to specify all valid |
| 136 | values for the field. In this case all possible values are described, |
| 137 | if the list is incomplete then the field is marked with the rsvdenum |
| 138 | key so the backend can take appropriate action. (If the enum field is |
| 139 | more than 7 bits then the checking is not done.) |
| 140 | |
| 141 | """ |
| 142 | |
| 143 | offset_intro = """ |
| 144 | |
| 145 | """ |
| 146 | |
| 147 | multi_intro = """ |
| 148 | |
| 149 | The multireg expands on the register required fields and will generate |
| 150 | a list of the generated registers (that contain all required and |
| 151 | generated keys for an actual register). |
| 152 | |
| 153 | """ |
| 154 | |
| 155 | window_intro = """ |
| 156 | |
| 157 | A window defines an open region of the register space that can be used |
| 158 | for things that are not registers (for example access to a buffer ram). |
| 159 | |
| 160 | """ |
| 161 | |
| 162 | regwen_intro = """ |
| 163 | |
| 164 | Registers can protect themselves from software writes by using the |
| 165 | register attribute regwen. When not an emptry string (the default |
| 166 | value), regwen indicates that another register must be true in order |
| 167 | to allow writes to this register. This is useful for the prevention |
| 168 | of software modification. The register-enable register (call it |
| 169 | REGWEN) must be one bit in width, and should default to 1 and be rw1c |
| 170 | for preferred security control. This allows all writes to proceed |
| 171 | until at some point software disables future modifications by clearing |
| 172 | REGWEN. An error is reported if REGWEN does not exist, contains more |
| 173 | than one bit, is not `rw1c` or does not default to 1. One REGWEN can |
Scott Johnson | 3976f9f | 2020-05-20 13:54:40 -0700 | [diff] [blame] | 174 | protect multiple registers. The REGWEN register must precede those |
| 175 | registers that refer to it in the .hjson register list. An example: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 176 | |
| 177 | ```hjson |
| 178 | { name: "REGWEN", |
| 179 | desc: "Register write enable for a bank of registers", |
| 180 | swaccess: "rw1c", |
| 181 | fields: [ { bits: "0", resval: "1" } ] |
| 182 | } |
| 183 | { name: "REGA", |
| 184 | swaccess: "rw", |
| 185 | regwen: "REGWEN", |
| 186 | ... |
| 187 | } |
| 188 | { name: "REGB", |
| 189 | swaccess: "rw", |
| 190 | regwen: "REGWEN", |
| 191 | ... |
| 192 | } |
| 193 | ``` |
| 194 | """ |
| 195 | |
| 196 | doc_tail = """ |
| 197 | |
| 198 | (end of output generated by `regtool.py --doc`) |
| 199 | |
| 200 | """ |
| 201 | |
| 202 | |
| 203 | def doc_tbl_head(outfile, use): |
Eunchan Kim | 0bd7566 | 2020-04-24 10:21:18 -0700 | [diff] [blame] | 204 | if use is not None: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 205 | genout(outfile, "\nKey | Kind | Type | Description of Value\n") |
| 206 | genout(outfile, "--- | ---- | ---- | --------------------\n") |
| 207 | else: |
| 208 | genout(outfile, "\nKey | Description\n") |
| 209 | genout(outfile, "--- | -----------\n") |
| 210 | |
| 211 | |
| 212 | def doc_tbl_line(outfile, key, use, desc): |
Eunchan Kim | 0bd7566 | 2020-04-24 10:21:18 -0700 | [diff] [blame] | 213 | if use is not None: |
Rupert Swarbrick | c02b52f | 2020-10-07 15:34:16 +0100 | [diff] [blame] | 214 | desc_key, desc_txt = desc |
| 215 | val_type = (validate.val_types[desc_key][0] |
| 216 | if desc_key is not None else None) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 217 | else: |
Rupert Swarbrick | c02b52f | 2020-10-07 15:34:16 +0100 | [diff] [blame] | 218 | assert isinstance(desc, str) |
| 219 | val_type = None |
| 220 | desc_txt = desc |
| 221 | |
| 222 | if val_type is not None: |
Weicai Yang | 53b0d4d | 2020-11-30 15:28:33 -0800 | [diff] [blame] | 223 | genout( |
| 224 | outfile, '{} | {} | {} | {}\n'.format(key, validate.key_use[use], |
| 225 | val_type, desc_txt)) |
Rupert Swarbrick | c02b52f | 2020-10-07 15:34:16 +0100 | [diff] [blame] | 226 | else: |
| 227 | genout(outfile, key + " | " + desc_txt + "\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 228 | |
| 229 | |
| 230 | def document(outfile): |
| 231 | genout(outfile, doc_intro) |
| 232 | for x in validate.val_types: |
| 233 | genout( |
| 234 | outfile, |
| 235 | validate.val_types[x][0] + " | " + validate.val_types[x][1] + "\n") |
| 236 | |
| 237 | genout(outfile, swaccess_intro) |
| 238 | doc_tbl_head(outfile, None) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 239 | for key, value in SWACCESS_PERMITTED.items(): |
| 240 | doc_tbl_line(outfile, key, None, value[0]) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 241 | |
| 242 | genout(outfile, hwaccess_intro) |
| 243 | doc_tbl_head(outfile, None) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 244 | for key, value in HWACCESS_PERMITTED.items(): |
| 245 | doc_tbl_line(outfile, key, None, value[0]) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 246 | |
Eunchan Kim | 0bd7566 | 2020-04-24 10:21:18 -0700 | [diff] [blame] | 247 | genout( |
| 248 | outfile, "\n\nThe top level of the JSON is a group containing " |
| 249 | "the following keys:\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 250 | doc_tbl_head(outfile, 1) |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 251 | for k, v in ip_block.REQUIRED_FIELDS.items(): |
| 252 | doc_tbl_line(outfile, k, 'r', v) |
| 253 | for k, v in ip_block.OPTIONAL_FIELDS.items(): |
| 254 | doc_tbl_line(outfile, k, 'o', v) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 255 | genout(outfile, top_example) |
| 256 | |
Pirmin Vogel | 1237a4e | 2020-06-23 09:07:28 +0200 | [diff] [blame] | 257 | genout( |
| 258 | outfile, "\n\nThe list of registers includes register definition " |
| 259 | "groups containing the following keys:\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 260 | doc_tbl_head(outfile, 1) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 261 | for k, v in register.REQUIRED_FIELDS.items(): |
| 262 | doc_tbl_line(outfile, k, 'r', v) |
| 263 | for k, v in register.OPTIONAL_FIELDS.items(): |
| 264 | doc_tbl_line(outfile, k, 'o', v) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 265 | genout(outfile, register_example) |
| 266 | |
Eunchan Kim | 0bd7566 | 2020-04-24 10:21:18 -0700 | [diff] [blame] | 267 | genout( |
| 268 | outfile, "\n\nIn the fields list each field definition is a group " |
Pirmin Vogel | 1237a4e | 2020-06-23 09:07:28 +0200 | [diff] [blame] | 269 | "itself containing the following keys:\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 270 | doc_tbl_head(outfile, 1) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 271 | for k, v in field.REQUIRED_FIELDS.items(): |
| 272 | doc_tbl_line(outfile, k, 'r', v) |
| 273 | for k, v in field.OPTIONAL_FIELDS.items(): |
| 274 | doc_tbl_line(outfile, k, 'o', v) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 275 | genout(outfile, field_example) |
| 276 | |
| 277 | genout(outfile, "\n\nDefinitions in an enumeration group contain:\n") |
| 278 | doc_tbl_head(outfile, 1) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 279 | for k, v in enum_entry.REQUIRED_FIELDS.items(): |
| 280 | doc_tbl_line(outfile, k, 'r', v) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 281 | |
| 282 | genout( |
Eunchan Kim | 0bd7566 | 2020-04-24 10:21:18 -0700 | [diff] [blame] | 283 | outfile, "\n\nThe list of registers may include single entry groups " |
| 284 | "to control the offset, open a window or generate registers:\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 285 | doc_tbl_head(outfile, 1) |
| 286 | for x in validate.list_optone: |
| 287 | doc_tbl_line(outfile, x, 'o', validate.list_optone[x]) |
| 288 | |
| 289 | genout(outfile, offset_intro) |
| 290 | genout(outfile, regwen_intro) |
| 291 | |
| 292 | genout(outfile, window_intro) |
| 293 | doc_tbl_head(outfile, 1) |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 294 | for k, v in window.REQUIRED_FIELDS.items(): |
| 295 | doc_tbl_line(outfile, k, 'r', v) |
| 296 | for k, v in window.OPTIONAL_FIELDS.items(): |
| 297 | doc_tbl_line(outfile, k, 'o', v) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 298 | |
| 299 | genout(outfile, multi_intro) |
| 300 | doc_tbl_head(outfile, 1) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 301 | for k, v in multi_register.REQUIRED_FIELDS.items(): |
| 302 | doc_tbl_line(outfile, k, 'r', v) |
| 303 | for k, v in multi_register.OPTIONAL_FIELDS.items(): |
| 304 | doc_tbl_line(outfile, k, 'o', v) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 305 | |
| 306 | genout(outfile, doc_tail) |