使用 C++23 从零实现 RISC-V 模拟器(5):CSR

👉🏻 文章汇总「从零实现模拟器、操作系统、数据库、编译器…」:https://okaitserrj.feishu.cn/docx/R4tCdkEbsoFGnuxbho4cgW2Yntc

RISC-V为每个hart定义了一个独立的控制状态寄存器(CSR)地址空间,提供了4096个独立的寄存器位置。每个hart都可以通过这个独立的CSR地址空间来配置、管理和监控其执行环境,实现对其控制状态的细粒度操作。

接下来讲解什么是 hart ,随后实现 CSR 。

Hart

在RISC-V架构中,"hart"是指硬件线程(Hardware Thread)的缩写。hart 表示在该架构中执行指令的硬件线程或处理器核心。

每个hart都是一个独立的执行单元,包含一套完整的处理器资源,如寄存器文件、执行单元和控制逻辑。RISC-V架构的设计允许多个harts同时存在,从而支持多核处理器。这种设计使得RISC-V在不同系统中可以以不同的方式配置,适应各种应用场景,从嵌入式系统到高性能计算。

让我们通过一个简单的例子来理解RISC-V hart的概念。假设我们有一个双核RISC-V处理器,其中每个核心都是一个独立的hart。在这个双核处理器中,可以同时执行两个不同的程序或任务,每个核心都有自己的寄存器文件、执行单元和缓存。

   +--------------------------+|      Core 0 (Hart 0)      ||                          ||   Register File, ALU,    ||   Cache, Control Logic   |+--------------------------+|+--------------------------+|      Core 1 (Hart 1)      ||                          ||   Register File, ALU,    ||   Cache, Control Logic   |+--------------------------+

在这个例子中,我们有两个harts,即两个独立的核心,每个核心都有自己的硬件资源。这允许并行执行两个不同的任务,提高了整个系统的性能。每个hart都有一个唯一的标识符(通常称为hart ID),以区分不同的硬件线程。

总体而言,RISC-V hart的概念体现了RISC-V架构的灵活性,使其能够适应各种不同的系统架构和应用需求,从而促进了RISC-V在各种计算平台上的广泛应用。

Hart 和 CPU 的关系

在RISC-V架构中,“hart”(硬件线程)和"CPU"(中央处理单元)之间存在一种直接关系,但它们并不完全等同。下面解释一下它们之间的关系:

  1. Hart(硬件线程): Hart是指在RISC-V处理器中独立的硬件执行线程。每个hart都有自己的寄存器文件(包括通用寄存器和特殊寄存器)、执行单元、控制逻辑等硬件资源。Hart的概念强调硬件执行线程的独立性,因此在一个多核RISC-V处理器中,每个核心就是一个独立的hart。

  2. CPU(中央处理单元): CPU是一个更广泛的术语,通常指整个中央处理单元,包括执行指令的硬件和相关的控制逻辑。在一个多核RISC-V处理器中,每个核心(hart)都有自己的CPU,因为它包含了执行指令所需的全部硬件资源。因此,一个多核RISC-V处理器中有多个CPU,每个CPU对应一个独立的hart。

简而言之,hart是CPU内部的硬件线程,一个多核RISC-V处理器中的每个核心就是一个hart,而每个hart都有自己的CPU。多个harts可以在同一处理器芯片上共存,共享一些系统资源(如内存),但它们是相对独立的硬件执行单元。

一个 CPU 对应一个 hart ?

不一定。在RISC-V架构中,一个CPU可以包含多个harts(硬件线程)。RISC-V的设计允许在一个物理处理器芯片上集成多个独立的hart,这些harts可以共享一些资源(如内存),但它们是相对独立的执行单元。

因此,一个物理CPU上可以有多个harts,每个hart都有自己的寄存器文件、执行单元和控制逻辑。这种设计支持多核处理器,其中每个核心都对应一个独立的hart。在这种情况下,一个物理CPU上的多个harts可以并行执行不同的任务,提高系统的整体性能。

总之,在RISC-V架构中,一个CPU可以包含一个或多个harts,这取决于具体的实现和系统设计。

特权级别

RISC-V架构定义了三种特权等级,这些等级对应于不同的操作系统和应用场景。这三种特权等级分别是:

  1. 用户态(User Mode): 用户态是RISC-V中最低特权等级。在用户态下,程序运行在用户空间,只能访问被允许的资源和寄存器。用户态是用于执行普通应用程序的特权级别。

  2. 监管态(Supervisor Mode): 监管态是RISC-V中介于用户态和机器态之间的特权等级。在监管态下,操作系统内核运行,具有更高的特权级别,可以执行特权指令,访问更多的寄存器和资源。监管态用于操作系统的内核代码执行。

  3. 机器态(Machine Mode): 机器态是RISC-V中最高的特权等级。在机器态下,处理器拥有最大的权限,可以执行所有指令、访问所有寄存器和系统资源。机器态主要用于处理器的初始化、系统的引导和一些底层的系统管理任务。

这些特权等级的引入旨在提供对处理器和系统资源的不同级别的访问权限。用户态提供了最低的权限,限制了对系统资源的直接访问,从而增加了系统的安全性。监管态在用户态和机器态之间提供了一个中间层,用于运行操作系统内核。机器态具有最高的权限,适用于系统的底层管理和初始化。

在RISC-V中,切换不同特权等级是通过特权级别切换的CSR(控制状态寄存器)指令来完成的。这些特权级别的设计使得RISC-V架构灵活适应不同的系统需求,从嵌入式系统到高性能计算。

hart 和特权级别

在RISC-V架构中,每个hart(硬件线程)在任意时刻都会运行在某种特权等级上。特权等级表示了该hart当前操作所拥有的权限级别,可以是用户态、监管态或机器态中的一种。

让我们通过一个简单的例子来理解这个概念。假设我们有一个RISC-V处理器,其中包含一个hart,并且这个处理器支持用户态、监管态和机器态这三种特权等级。

在处理器启动时,该hart可能最初处于机器态,执行一些底层的系统初始化任务。随后,当执行用户程序时,该hart可能切换到用户态,其中它只能访问被允许的资源。当用户程序需要进行某些系统调用或需要执行特权指令时,该hart可能会通过修改CSR(控制状态寄存器)的值来切换到监管态,从而提升其权限级别。在监管态中,hart可以执行一些操作系统内核的任务。

在上述例子中,特权等级的切换通过修改CSR完成,CSR中保存了当前hart所在的特权等级。这样的设计允许系统在运行时动态地切换特权等级,从而灵活地管理和调整系统的运行状态。

总体而言,RISC-V的特权等级概念提供了一种灵活的机制,使得不同任务和系统级别的代码可以在同一个hart上运行,同时确保系统的安全性和稳定性。在后续章节中,对特权等级的更详细讨论可能会涉及到CSR的具体使用和特权级别切换的细节。

CSR

Hart(硬件线程)和CSR(控制状态寄存器)之间的关系在RISC-V架构中非常密切。CSR用于配置、管理和监控每个hart的执行环境,确保对系统行为的细粒度控制。以下是hart和CSR之间关系的一些关键点:

  1. Hart的独立性: 每个hart都有自己独立的CSR空间。这意味着每个硬件线程可以配置和控制其自身的状态,而不会直接影响其他harts。

  2. CSR用于配置和控制: CSR包含一系列寄存器,用于控制和配置hart的各个方面,例如中断使能、时钟设置、异常处理等。通过对CSR的读写,软件可以调整和管理每个hart的执行环境。

  3. 特权级别切换: CSR中的一些寄存器用于管理hart的特权级别。通过修改这些寄存器的值,可以在用户态、监管态和机器态之间切换,提供不同特权级别下的权限和访问控制。

  4. 上下文保存与恢复: CSR中的一些寄存器用于保存和恢复hart的上下文信息。在上下文切换时,处理器会保存当前hart的状态到CSR中,然后加载新任务的状态。

  5. 中断和异常处理: CSR也与中断和异常处理相关。中断使能、中断掩码等设置都通过CSR进行。当发生中断或异常时,相关的状态信息也会被保存到CSR中,以便后续的处理程序能够正确执行。

总体而言,CSR为每个hart提供了一个独立的、可编程的控制接口,用于管理和配置其执行环境。这种设计允许系统在运行时动态地调整每个hart的状态,提供了对系统行为更细粒度的控制。在多核处理器中,每个hart都可以通过CSR实现对自身的独立配置和控制。

设计 CSR

Csr类是一个用于处理RISC-V架构中的控制和状态寄存器(CSR)的类。在RISC-V架构中,CSR是一种特殊类型的寄存器,用于控制处理器的各种功能,包括中断处理、异常处理、性能监视等。下面是 CSR 对应的头文件。

class Csr {
public:Csr();  // 构造函数void dump_csrs() const;  // 打印所有的CSRuint64_t load(size_t addr) const;  // 加载指定地址的CSRvoid store(size_t addr, uint64_t value);  // 存储值到指定地址的CSRbool is_medelegated(uint64_t cause) const;  // 检查是否有机器异常委托bool is_midelegated(uint64_t cause) const;  // 检查是否有机器中断委托private:std::array<uint64_t, NUM_CSRS> csrs;  // 存储CSR的数组
};

在 Cpu.h 中增加 Csr 成员变量,并且更新构造函数,增加 Csr 对应的成员构造函数。

Csr::load

下面代码是Csr类中的load方法的实现。Csr类表示控制状态寄存器(CSR)。

load方法接受一个地址作为参数,然后返回该地址的CSR的值。这个方法使用了一个switch语句来处理不同的地址。

  • 当地址是SIE时,它返回MIE寄存器和MIDELEG寄存器的位与结果。这表示获取中断使能状态。
  • 当地址是SIP时,它返回MIP寄存器和MIDELEG寄存器的位与结果。这表示获取中断挂起状态。
  • 当地址是SSTATUS时,它返回MSTATUS寄存器和MASK_SSTATUS的位与结果。这表示获取特权级状态。
  • 对于其他地址,它直接返回该地址的CSR的值。

这个方法的返回类型是uint64_t,表示它返回一个64位的无符号整数。

uint64_t Csr::load(size_t addr) const {switch (addr) {case SIE:return csrs[MIE] & csrs[MIDELEG];case SIP:return csrs[MIP] & csrs[MIDELEG];case SSTATUS:return csrs[MSTATUS] & MASK_SSTATUS;default:return csrs[addr];}
}

在这段代码中,SIESIPSSTATUS是控制状态寄存器(CSR)的地址。这些地址对应的CSR有特殊的含义和用途。

  • SIE(Supervisor Interrupt Enable):这是一个控制寄存器,用于控制在Supervisor模式下哪些中断是被允许的。在这段代码中,csrs[MIE] & csrs[MIDELEG]表示获取在MIE(Machine Interrupt Enable)寄存器中被允许并且在MIDELEG(Machine Interrupt Delegation)寄存器中被委托到Supervisor模式的中断。

  • SIP(Supervisor Interrupt Pending):这是一个状态寄存器,用于表示在Supervisor模式下哪些中断是挂起的。在这段代码中,csrs[MIP] & csrs[MIDELEG]表示获取在MIP(Machine Interrupt Pending)寄存器中被挂起并且在MIDELEG寄存器中被委托到Supervisor模式的中断。

  • SSTATUS(Supervisor Status):这是一个状态寄存器,用于保存和恢复Supervisor模式下的状态。在这段代码中,csrs[MSTATUS] & MASK_SSTATUS表示获取MSTATUS(Machine Status)寄存器中的Supervisor模式的状态。

这些寄存器在处理中断和异常,以及在不同的特权级之间切换时非常重要。

CSR 指令

CSR 指令是 RISC-V 架构中的 CSR(Control and Status Register)指令,用于对控制和状态寄存器进行读取、写入和修改。以下是每个指令的简要说明:

  1. csrrw(CSR Read and Write):

    • 格式:csrrw rd, csr, rs1
    • 作用:将控制和状态寄存器(CSR)csr 的当前值读取到寄存器 rd 中,并将 rs1 中的值写入到 CSR csr
    • 示例汇编代码:
      csrrw x3, mstatus, x1
      
  2. csrrs(CSR Read and Set):

    • 格式:csrrs rd, csr, rs1
    • 作用:将控制和状态寄存器(CSR)csr 的当前值读取到寄存器 rd 中,并将 rs1 中的值设置为 CSR csr 的位。
    • 示例汇编代码:
      csrrs x5, mstatus, x2
      
  3. csrrc(CSR Read and Clear):

    • 格式:csrrc rd, csr, rs1
    • 作用:将控制和状态寄存器(CSR)csr 的当前值读取到寄存器 rd 中,并将 rs1 中的值清零 CSR csr 的相应位。
    • 示例汇编代码:
      csrrc x7, mstatus, x3
      
  4. csrrwi(CSR Read and Write Immediate):

    • 格式:csrrwi rd, csr, zimm
    • 作用:将控制和状态寄存器(CSR)csr 的当前值读取到寄存器 rd 中,并将立即数 zimm 写入到 CSR csr
    • 示例汇编代码:
      csrrwi x9, mstatus, 5
      
  5. csrrsi(CSR Read and Set Immediate):

    • 格式:csrrsi rd, csr, zimm
    • 作用:将控制和状态寄存器(CSR)csr 的当前值读取到寄存器 rd 中,并将立即数 zimm 设置为 CSR csr 的位。
    • 示例汇编代码:
      csrrsi x11, mstatus, 2
      
  6. csrrci(CSR Read and Clear Immediate):

    • 格式:csrrci rd, csr, zimm
    • 作用:将控制和状态寄存器(CSR)csr 的当前值读取到寄存器 rd 中,并将立即数 zimm 清零 CSR csr 的相应位。
    • 示例汇编代码:
      csrrci x13, mstatus, 1
      

这些指令允许程序在运行时操作控制和状态寄存器,从而改变处理器的行为和状态。在示例中,mstatus 是一个控制和状态寄存器的例子,实际使用时会根据具体的需求选择不同的 CSR。

使用场景

RISC-V 中的 CSR(Control and Status Register)指令主要用于处理器内部的控制和状态寄存器的读取、写入和修改。这些寄存器用于管理和监控处理器的运行状态。以下是一些 CSR 指令的使用场景:

  1. 系统控制和状态管理:

    • csrrwcsrrscsrrc 指令允许程序读取、设置和清除系统控制和状态寄存器,例如 mstatus 寄存器,以控制系统的运行状态。
  2. 中断和异常处理:

    • CSR 指令用于配置和管理中断、异常和处理器的状态。通过读写 mie(Machine Interrupt Enable)、mip(Machine Interrupt Pending)等寄存器,可以启用或禁用中断,检查中断状态等。
  3. 性能计数器:

    • RISC-V 架构中的 CSR 指令允许程序读取和配置性能计数器,例如 cycletime,以用于性能分析和优化。
  4. 用户模式切换:

    • CSR 指令可用于切换处理器的执行模式,例如从用户模式到特权模式。mstatus 中的相关位可以通过 CSR 指令进行设置或清除。
  5. 随机数生成:

    • 一些 CSR 指令可以用于生成随机数,例如 misa(Machine ISA Register)。
  6. 访存权限管理:

    • 一些 CSR 寄存器用于管理访存权限,例如 satp(Supervisor Address Translation and Protection)寄存器,它用于设置虚拟内存地址转换和内存保护。
  7. 环境保存和恢复:

    • CSR 指令可用于保存和恢复处理器的上下文环境,例如通过 mepc(Machine Exception Program Counter)保存异常处理程序的返回地址。
  8. 系统调试:

    • CSR 指令还可以用于系统调试,例如通过 dcsr(Debug Control and Status Register)进行调试模式的配置。

这些使用场景展示了 CSR 指令在处理器内部控制和状态管理中的多样性和重要性。不同的 CSR 寄存器提供了对处理器不同方面的控制和监控。

指令解析及对应的单元测试

下面是 CSRRW 指令对应的解析代码及其单元测试。没有完全列出,完整代码可以去对应分支 https://github.com/weijiew/crvemu/tree/lab5-csr 查看。

std::optional<uint64_t> executeCSR_RW(Cpu& cpu, uint32_t inst) {auto [rd, rs1, rs2] = unpackInstruction(inst);auto csr_addr = (inst & 0xfff00000) >> 20;// Load the value from the CSR registeruint64_t t = cpu.csr.load(csr_addr);// Store the value from the rs1 register into the CSR registercpu.csr.store(csr_addr, cpu.regs[rs1]);// Store the original CSR value into the rd registercpu.regs[rd] = t;// Update the program counterreturn cpu.update_pc();
}// Test csrrw instruction
TEST(RVTests, TestCsrrw) {{std::string code = start +"addi x2, x0, 5 \n"    // Load 5 into x2"csrrw x1, mstatus, x2 \n";  // x1 = mstatus; mstatus = x2;Cpu cpu = rv_helper(code, "test_csrrw", 2);// Verify if MSTATUS register has the correct valueEXPECT_EQ(cpu.getRegValueByName("mstatus"), 5) << "Error: mstatus should be 5 after CSRRW instruction";}
}

总结

这部分内容增加了 CSR 相关的寄存器,通过 CPU 可以直接读取,此外增加了六个 CSR 相关的指令解析及其对应的单元测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/688326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序列表下拉刷新和加载更多

配置 在小程序的app.json中&#xff0c;检查window项目中是否已经加入了"enablePullDownRefresh": true&#xff0c;这个用来开启下拉刷新 "window": {"backgroundTextStyle": "light","navigationBarBackgroundColor": &q…

unity C#中的封装、继承和多态简单易懂的经典实例

文章目录 封装 (Encapsulation)继承 (Inheritance)多态 (Polymorphism) C#中的封装、继承和多态是面向对象编程&#xff08;OOP&#xff09;的三大核心特性。下面分别对这三个概念进行深入解释&#xff0c;并通过实例来说明它们在实际开发中的应用。 封装 (Encapsulation) 实例…

【北京航空航天大学】【信息网络安全实验】【实验一、密码学:DES+RSA+MD5编程实验】

信息网络安全实验 实验一、DES RSA MD5 一、实验目的 1. 通过对DES算法的代码编写,了解分组密码算法的设计思想和分组密码算法工作模式; 2. 掌握RSA算法的基本原理以及素数判定中的Rabin-Miller测试原理、Montgomery快速模乘(模幂)算法,了解公钥加密体制的优缺点及其常…

gem5学习(21):索引策略——Indexing Policies

目录 一、集合关联&#xff08;Set Associative&#xff09; 二、倾斜关联&#xff08;Skewed Associative&#xff09; 索引策略确定基于地址将一个块映射到哪个位置。 索引策略的最重要方法是getPossibleEntries()和regenerateAddr()&#xff1a; getPossibleEntries()用…

数组转二叉树的一种方法-java(很特殊)

上代码 Node节点的代码 public class ThreadNode {private int data;private ThreadNode left;private boolean leftTag; // 左子节点是否为线索private ThreadNode right;private boolean rightTag; // 右子节点是否为线索// ... 省略get和set方法// ... 省略构造方法// ... …

【MySQL】学习多表查询和笛卡尔积

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-N8PeTKG6uLu4bJuM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Linux命令-netstat

用于端口和服务之间的故障排除 格式&#xff1a;netstat [常用参数] | grep 端口号/进程名称 -n&#xff1a;显示接口和端口的编号 -t&#xff1a;显示TCP套接字 -u&#xff1a;显示UDP套接字 -l&#xff1a;显示监听中的套接字 -p&#xff1a;显示端口对应的进程信息 -a&a…

一些常见的激活函数介绍

文章目录 激活函数1. sigmoid2. relu3. leakyReLu4. nn.PReLU5. nn.ReLU66. Softplus函数7. softmin, softmax, log softmax8. ELU 激活函数 1. sigmoid https://zhuanlan.zhihu.com/p/172254089 sogmoid函数的梯度范围在 0-0.25&#xff0c; 容易梯度消失 2. relu ReLU激…

1.函数模板基础

1.1函数模板作用&#xff1a; 建立一个通用函数&#xff0c;其函数返回值类型和形参类型可以不具体指定&#xff0c;用一个虚拟的类型来代表&#xff0c;提高复用性 1.2语法&#xff1a; //第一种 template <typename T> 函数声明或定义//第二种 template <class T&…

AI趋势(06) Sora,AI对世界的新理解

说明&#xff1a;使用 黄金圈法则学习和解读Sora&#xff08;what、why、how&#xff09; 1 Sora是什么&#xff1f; 1.1 Sora的基本解读 Sora是OpenAl在2024年2月16日发布的首个文本生成视频模型。该模型能够根据用户输入的文本自动生成长达60秒的1080p复杂场景视频&#xf…

Android稳定性相关知识

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、相关方法论3.1 crash3.2 性能3.3 高…

Python:异常处理

异常处理已经成为判断一门编程语言是否成熟的标准&#xff0c;除传统的像C语言没有提供异常机制之外&#xff0c;目前主流的编程语言如Python、Java、Kotlin等都提供了成熟的异常机制。异常机制可以使程序中的异常处理代码和正常业务代码分离&#xff0c;保证代码更加优雅&…

Linux中MySQL表名与@TableName中大小写关系

在使用SpringBoot时&#xff0c;我们普遍会使用注解&#xff0c;实体类中使用注解TableName指明表&#xff0c;以下是TableName的一些注意事项。 【说明】 在MySQL中&#xff0c;表名的大小写处理与操作系统和数据库服务器的配置有关。MySQL默认是在Linux系统上区分大小写的&…

2024年重磅消息:来自OpenAI发布的视频生成模型Sora

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Jupyter的全面探索:从入门到高级应用

1. 引言 Jupyter项目的简介 Jupyter项目是一个开源项目&#xff0c;旨在为科学计算、数据分析和教育提供交互式计算和数据科学环境。它允许用户创建和共享包含实时代码、方程、可视化以及叙述性文本的文档&#xff0c;这些文档被称为“笔记本”。Jupyter支持超过40种编程语言…

自然语言编程系列(一):自然语言和程序语言介绍

1.自然语言和程序语言 自然语言和程序语言是两种截然不同但又相互关联的语言体系&#xff0c;它们分别服务于人类日常交流和计算机指令执行。 自然语言&#xff1a; 定义&#xff1a;自然语言是指人类在日常生活中使用的语言&#xff0c;如英语、汉语、法语等。它是非正式且灵…

Java的跨平台特性

Java语言特别流行的其中一个原因就是其具有良好的跨平台性&#xff0c;Java的跨平台性表现在通过 Java 语言编写的应用程序在不同的系统平台上都能够正常运行。其原理是&#xff1a;只要在需要运行 java 应用程序的操作系统上&#xff0c;先安装一个 Java 虚拟机(JVM Java Virt…

html表格标签(下):lable标签,select标签和textara标签

html表格标签(下)&#xff1a;lable标签&#xff0c;select标签和textarea标签 lable标签 搭配 input 使用,点击 label 标签就能选中对应的单选/复选框, 能够提升用户体验。 for 属性: 指定当前 label 和哪个相同 id 的 input 标签对应 (此时点击才是有用的) 运行效果&#x…

信息安全认证 | CISP证书怎么样?值得考吗?

HCIE考证研究所的朋友们&#xff0c;新年快乐&#xff01; 今天给大家说说CISP证书&#xff0c;新的一年祝大家逢考必过啊~ 01 考注册信息安全工程师证书的用处 CISP证书可作为学识和技能证明&#xff1b;求职、任职、晋升、加薪的资格凭证&#xff1b;用人单位招聘、录用劳动…

VueTreeselect 只能选择末级节点

场景&#xff1a;有些需求会要求只能选择末级节点。 解决办法&#xff1a;设置disable-branch-nodes为true。 <treeselectv-model"form.deptIds":options"deptOptions":show-count"true":limit"5"placeholder"请选择部门&quo…