文档

从子系统生成可重入代码

通过将子系统配置为作为参数传递数据的可重用函数,可以减少代码生成器为相同的原子子系统生成的代码量(例如,rtB_ *对于块输入和输出,rtDW_ *对于连续状态,和rtP_ *对于参数)。默认情况下,代码生成器生成子系统代码,子系统代码通过共享访问共享内存中的全局数据结构与其他代码通信。通过将数据作为参数传递,代码可以重入。代码的每个实例都维护自己的惟一数据。

为了配置子系统的可重用性和可重入性,请以相同的方式配置相同子系统的掩码和块参数。代码生成器执行校验和以确定子系统是否相同以及代码是否可重用。如果代码是可重用的,代码生成器将生成可重用的、可重入的函数代码的单个实例。

配置子系统块参数。

  1. 如果子系统为虚拟子系统,请选择将其视为原子单位(万博1manbetxSimulink)来启用函数打包参数。

  2. 代码生成选项卡,设置函数包装(万博1manbetx模型)可重用的功能.代码生成器为每个子系统生成带有参数的单独函数。选择可重用的功能还启用其他参数,可用于控制代码生成器为子系统代码生成的函数和文件的名称。

  3. 函数名选项(万博1manbetx模型)。要生成可重用的、可重入的代码,请为相同的子系统指定相同的设置。

    • 若要让代码生成器确定函数名,请选择汽车

    • 若要使用子系统名称,或对于库块,使用库块的名称,请选择使用子系统名称

    • 显示函数名(万博1manbetxSimulink)参数,并输入唯一有效的C/ c++函数名,选择用户指定的

    如果在模型引用层次结构中有相同子系统的多个实例,请选择汽车

    如果你使用嵌入式编码器®,可以使用标识符格式控件。看到标识符格式控制(嵌入式编码)。

  4. 文件名选项(万博1manbetx模型)。要生成可重用的、可重入的代码,请为相同的子系统指定相同的设置。

    • 让代码生成器决定文件命名选择汽车

    • 若要使用子系统名称,或对于库块,则选择库块的名称使用子系统名称

    • 使用函数名,如所指定的函数名选项选择使用函数名

    • 显示文件名称(无扩展名)(万博1manbetxSimulink)参数,输入文件名称,不包括扩展名(例如:.c. cpp)选择用户指定的

    其他注意事项:

    • 如果在模型引用层次结构中有相同子系统的多个实例,请选择汽车

    • 如果代码生成器没有为子系统生成单独的文件,则函数代码将放在子系统的父系统生成的文件中。如果父类是模型本身,代码生成器将函数代码放在其中模型.c模型. cpp

    • 如果生成的代码处于源代码控制之下,请指定一个值汽车.该规范防止在修改和重新构建模型时更改生成的文件名。

    • 如果您选择使用子系统名称,如果模型包含model块,或者正在为模型生成模型引用目标,代码生成器将修改子系统文件名。在这些情况下,代码生成器使用文件名模型子系统.c

如果子系统A有mask参数b而且K子系统B有掩码参数c而且K,代码重用是不可能的。代码生成器为子系统A和B生成单独的函数。如果为子系统A和B设置不同的块参数,代码重用是不可能的。

限制

  • 代码生成器使用校验和来确定子系统是否相同且可重用。子系统代码不能被重用,如果:

    • 在块和数据对象中,使用符号指定尺寸。

    • 端口在各个子系统之间有不同的采样时间、数据类型、复杂性、帧状态或维度。

    • 子系统的输出被标记为全局信号。

    • 子系统包含具有不同名称或参数设置的相同块。

    • 子系统的输出连接到合并块的输出合并block配置了一个自定义存储类,该类在C代码中实现为不可寻址内存(例如,设置).

    • 子系统的输入是非标量的,并配置了一个自定义存储类,该类在C代码中实现为不可寻址内存。

    • 一个被屏蔽的子系统有一个非标量的参数,并且配置了一个自定义存储类,这个类在C代码中实现为不可寻址内存。

    • 函数调用子系统在设置模型配置参数时使用掩码参数默认参数行为可调.要重用掩码函数调用子系统,请将其放置在没有掩码的新原子子系统中。然后将Trigger块从屏蔽子系统移动到原子子系统。

    • 子系统中的块使用部分可调表达式.一些部分可调表达式禁止代码重用。

      部分可调表达式是包含一个或多个可调变量和一个不可调表达式的表达式。例如,假设您创建了可调变量K与价值15.23还有可调变量P与价值(5、7、9).表达式K + P '部分可调表达式是因为表达式P '不可调。有关可调表达式限制的详细信息,请参见可调表达式限制

  • 对于包含可重用的s功能块的子系统,这些块必须满足中列出的要求支持代码重用的s -函数万博1manbetx(嵌入式编码)。

  • 如果您选择可重用的功能,并且代码生成器确定您不能为子系统重用代码,它将生成一个不可重用的单独函数。代码生成报告可能显示单独的函数是可重用的,即使只有一个子系统使用它。如果您希望在这种情况下代码生成器内联子系统代码(而不是作为函数部署),请设置函数包装(万博1manbetx模型)汽车

  • 如果可重用子系统使用共享的本地数据存储,并且为模型数据元素配置默认映射,则将默认存储类映射保留为类别共享本地数据存储设置为默认的

确定子系统代码不被重用的原因

由于中所述的限制从子系统生成可重入代码,代码生成器可能不会像您期望的那样重用生成的代码。要确定为什么为子系统生成的代码不能重用:

  1. 检查代码生成报告的子系统部分。

  2. 比较子系统校验和数据。

HTML代码生成报告的审查子系统部分

如果代码生成器没有将子系统的代码生成为可重用代码,并且您将子系统配置为可重用的,请检查代码生成报告的子系统部分(参见生成一个代码生成报告).子系统部分包含:

  • 一个总结了如何将非虚拟子系统转换为生成代码的表。

  • 描述为什么子系统不能作为可重用代码生成的诊断信息。

子系统部分还将模型中的非内联子系统映射到生成代码中的函数或重用函数。例如,打开并构建rtwdemo_atomic模型。

比较子系统校验和数据

您可以通过比较子系统校验和数据来确定子系统代码不能重用的原因。代码生成器通过比较子系统校验和来确定子系统是否相同,如中所述限制.对于跨引用模型的子系统重用,此过程可能不会标记每个差异。

考虑这个模型,rtwdemo_ssreuse魔法石,第1章而且SS2是同一子系统的实例。在这两个实例中都是子系统参数函数包装设置为可重用的功能

使用方法万博1manbetxSimulink.SubSystem.getChecksum获取子系统的校验和。检查结果以确定代码没有被重用的原因。

  1. 打开模型rtwdemo_ssreuse.在您有写权限的文件夹中保存模型的副本。

  2. 关联子系统魔法石,第1章而且SS2华东桐柏.对于每个子系统,在模型窗口中,选择子系统。当选择子系统时,在命令窗口中输入:

    SS1 = gcb;
    SS2 = gcb;
  3. 使用方法万博1manbetxSimulink.SubSystem.getChecksum来获取每个子系统的校验和。该方法返回两个输出值:校验和值和用于计算校验和的输入的详细信息。

    [chksum1, chksum1_details] =…万博1manbetxSimulink.SubSystem.getChecksum(魔法石,第1章);[chksum2, chksum2_details] =…万博1manbetxSimulink.SubSystem.getChecksum (SS2);
  4. 比较两个校验和值。这些值应该根据子系统配置相等。

    Isequal (chksum1, chksum2) ans = 1
  5. 使用万博1manbetxSimulink.SubSystem.getChecksum为了确定两个子系统校验和不同的原因,可以修改SS1输出端口的数据类型模式,使其与SS2输出端口的数据类型模式不同。

    1. 看…的面具下魔法石,第1章.右键单击子系统。在上下文菜单中,选择面具面具下的样子

    2. 在子系统框图中,双击查找表块,打开“子系统参数”对话框。

    3. 点击数据类型

    4. 选择饱和整数溢出并点击好吧

  6. 的校验和魔法石,第1章.比较两个子系统的校验和。这一次,校验和不相等。

    [chksum1, chksum1_details] =…万博1manbetxSimulink.SubSystem.getChecksum(魔法石,第1章);Isequal (chksum1, chksum2) ans = 0
  7. 在确定校验和不同之后,找出原因。的仿真软万博1manbetx件®引擎使用信息(如信号数据类型、一些块参数值和块连接信息)来计算校验和。要确定校验和不同的原因,请比较计算校验和值的数据。返回的第二个值可以获得此信息万博1manbetxSimulink.SubSystem.getChecksum,它是一个有四个字段的结构数组。

    看看结构chksum1_details

    chksum1_details chksum1_details = ContentsChecksum: [1x1 struct] InterfaceChecksum: [1x1 struct] ContentsChecksumItems: [287x1 struct] InterfaceChecksumItems: [53x1 struct]

    ContentsChecksum而且InterfaceChecksum子系统校验和的组件校验和。剩下的两个字段,ContentsChecksumItems而且InterfaceChecksumItems,包含校验和详细信息。

  8. 确定子系统内容、接口或两者中是否存在差异。例如:

    isequal (chksum1_details.ContentsChecksum.Value……chksum2_details.ContentsChecksum.Value) ans = 0 isequal(chksum1_details. interfacececksum . value,…chksum2_details.InterfaceChecksum.Value) ans = 1

    在这种情况下,内容存在差异。

  9. 编写一个类似于此脚本的脚本来查找差异。

    idxForCDiffs = [];if (~strcmp(chksum1_details.ContentsChecksumItems(idx)).长度(chksum1_details.ContentsChecksumItems)。标识符,…chksum2_details.ContentsChecksumItems(idx).Identifier)) disp(['内容项的标识符不同',num2str(idx)]);idxForCDiffs = [idxForCDiffs, idx];结束if (ischar(chksum1_details.ContentsChecksumItems(idx). value)) if (~strcmp(chksum1_details.ContentsChecksumItems(idx). value))价值,……chksum2_details.ContentsChecksumItems(idx).Value)) disp(['内容项的字符向量值不同',num2str(idx)]);idxForCDiffs = [idxForCDiffs, idx];结束结束if (isnumeric(chksum1_details.ContentsChecksumItems(idx). value)) if (chksum1_details.ContentsChecksumItems(idx). value)值~=…chksum2_details.ContentsChecksumItems(idx).Value) disp(['内容项的数值不同',num2str(idx)]);idxForCDiffs = [idxForCDiffs, idx]; end end end
  10. 运行脚本。该示例假设您为脚本命名check_details

    内容项202的字符向量值不同

    结果表明,索引项202在子系统内容中存在差异。

  11. 使用返回的索引值获取找到的每个差异的句柄、标识符和值详细信息。

    chksum1_details.ContentsChecksumItems(202) ans =句柄:'rtwdemo_ssreuse/SS1/Lookup Table'标识符:'SaturateOnIntegerOverflow'值:'on'

    细节标识查找表块参数饱和整数溢出作为调试子系统重用问题的重点。

相关的话题

这个话题有用吗?