Skip to content

CSR length is computed without U or VU mode, and max_length raises on a core without the M extension #2463

Description

ConfiguredArchitecture#multi_xlen_in_mode? (tools/ruby-gems/udb/lib/udb/cfg_arch.rb:103) answers "can the effective XLEN change in this mode" for M, S, U, VS and VU, with explicit handling for unconfigured, partially configured and fully configured architectures. CsrField#dynamic_location? (csr_field.rb:380) uses it, over Csr#modes_with_access.

Csr answers the same question itself, from the length token, in five places: dynamic_length?, max_length, length_cond32, length_cond64 and length_pretty. None of the five considers U or VU mode.

Everything below is on main at 858ae306, reproduced with the config at the end.

1. A register and its own fields disagree

In a config where the only mutable mode XLEN is UXLEN, 8 of 396 CSRs report dynamic_length? == false while at least one of their fields reports dynamic_location? == true:

ssp, jvt, vl, vlenb, vstart, vtype, vxrm, vxsat

All eight are priv_mode: U, so modes_with_access returns ["M", "S", "U", "VS", "VU"]. The field asks about five modes; the register asks about three.

The conditions that get emitted are wrong in U-mode:

  • ssp and jvt are length: XLEN, and length_cond32 produces
    (priv_mode() == PrivilegeMode::M && CSR[misa].MXL == 0) || (priv_mode() == PrivilegeMode::S && CSR[mstatus].SXL == 0) || (priv_mode() == PrivilegeMode::VS && CSR[hstatus].VSXL == 0).
    Executing in U-mode every disjunct is false regardless of mstatus.UXL.
  • vl, vlenb, vstart, vtype, vxrm, vxsat are length: MXLEN, and length_cond32 produces CSR[misa].MXL == 0, which is MXLEN for a register whose width follows the current mode.

Those strings reach backends/cfg_html_doc/templates/csr.adoc.erb, backends/portfolio/templates/csr_appendix.adoc.erb, backends/prm_pdf/templates/csr.adoc.erb, tools/ruby-gems/udb-gen/templates/common/csr.adoc.erb and tools/ruby-gems/udb-gen/templates/manual/csr.adoc.erb.

2. max_length tests for the multiply extension where it means M-mode

The XLEN branch of max_length opens with

if cfg_arch.possible_extensions.map(&:name).include?("M")

commented as "must always have M-mode". spec/std/isa/ext/M.yaml is Integer multiply and divide; machine mode is Sm. cfgs/qc_iu.yaml lists both as separate extensions.

Taking the config below and changing one thing, whether M is prohibited:

prohibited max_length for the 9 length: XLEN CSRs
S, H all return 64
S, H, M all raise RuntimeError: Unexpected from csr.rb:335

The nine are hcontext, jvt, mscontext, scontext, ssp, tdata1, tdata2, tdata3, tselect. A core without integer multiply is ordinary, and it cannot compute the width of tselect.

3. UXLEN and VUXLEN cannot be expressed

spec/std/isa/param/UXLEN.yaml and VUXLEN.yaml both exist, and config.rb:341 declares MODE_XLEN_PARAMS = %w[UXLEN SXLEN VSXLEN VUXLEN]. But spec/schemas/csr_schema.json allows length to be only [32, 64, "MXLEN", "SXLEN", "VSXLEN", "XLEN"], and csr.rb carries seven raise "Unexpected length" sites. A CSR cannot say its width follows U-mode.

Of the 76 CSRs with priv_mode: U, 67 carry a fixed 32 or 64 and nine carry a mode-relative length. Those nine split two ways: seven say length: MXLEN (vcsr, vl, vlenb, vstart, vtype, vxrm, vxsat) and two say length: XLEN (jvt, ssp). The schema describes XLEN as "the effective XLEN in the current execution mode", so those two groups answer the same question differently.

Reproducer

# repro.yaml
---
$schema: config_schema.json#
kind: architecture configuration
type: partially configured
name: uxl_only
description: RV64, only UXLEN mutable, S and H prohibited
params:
  MXLEN: 64
  UXLEN: [32, 64]
mandatory_extensions:
  - name: "I"
    version: ">= 0"
  - name: "Sm"
    version: ">= 0"
  - name: "U"
    version: ">= 0"
prohibited_extensions:
  - name: "S"
    version: ">= 0"
  - name: "H"
    version: ">= 0"
cfg_arch = resolver.cfg_arch_for(Pathname.new("repro.yaml"))

cfg_arch.multi_xlen_in_mode?("U")   # => true
cfg_arch.possible_xlens             # => [32, 64]

cfg_arch.csrs.select { |c|
  c.dynamic_length? == false && c.fields.any?(&:dynamic_location?)
}.map(&:name).sort
# => ["jvt", "ssp", "vl", "vlenb", "vstart", "vtype", "vxrm", "vxsat"]

Adding M to prohibited_extensions turns every max_length call on a length: XLEN CSR into a RuntimeError.

Question before a fix

Is XLEN intended to mean the effective XLEN of whichever mode is executing, as the schema description says? If so, the seven vector CSRs carrying length: MXLEN are mis-tagged, and UXLEN/VUXLEN never need to enter the enum. If not, the enum needs them, the way MODE_XLEN_PARAMS already assumes.

The tooling fix looks the same either way: have Csr ask multi_xlen_in_mode? over modes_with_access instead of keeping a parallel implementation, which would also remove the condition string that is currently written out three times. The data change depends on the answer, so I would keep it to a separate PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions