TLC语言

TLC语言

Simulink模型在Simulink模型在Simulink Coder和Embedded Coder的支持下可以生成嵌入式C代码;模型生成代码需要靠系统目标文件与模块目标文件的支持,这两个等级的目标文件都是由TLC进行语言转换的TLC文件。TLC语言(解释性语言)拥有目标语言转换的能力。

TLC的作用

TLC语言最根本的作用是将模型编译出来的rtw文件转化为支持某种平台或硬件的代码

  1. 支持模型针对通用或特定目标硬件的代码生成功能;
  2. 为S函数模块提供代码生成功能,可以让用户自己增加支持代码生成的模块;
  3. 在代码生成过程中,生成不依赖S函数模块的自定义过程代码。

TLC的语法

TLC是一种以单个%打头的关键字为命令,空格之后跟参数的脚本语言,自身包含了流控制语法,内建函数,关键字和常用命令,支持脚本和函数两种编程方式

基本语法

[text | %<expression>]*
% text表示字符串,将原原本本的展开到输出流。在%<>之中的是TLC变量,通过%<>作用将变量的执行结果显示到输出流
%keyword[argement1, argument2,...]
% %kewword表示TLC语言中的命令符,[argument1, argument2,...]中则表示这个命令符所操作的参数
%assign Str = "Hello World";
% %assign表示其后的语句是对变量赋值
%warning,%error,%trace命令,可以将其后所跟变量或字符串的内容输出
% tlc xxxx.tlc是运行脚本TLC文件的方法,脚本TLC文件是指可以直接运行的TLC文件
% %error命令和%warning命令使用方法基本相同,只是在输出内容前自动增加error,并非warning的字样,并且会给出TLC报错信息
% 使用%trace命令代替%warning命令显示信息,在执行TLC文件时需要增加-v或-vl才能将%trace的命令给显示出来
% TLC语言有两个内建宏TLC_TRUE = 1和TLC_FALSE = 0,在TLC语言的编写中会经常遇到

常用指令

注释:TLC语句可以通过双百分号进行单行注释,%% comment

可以通过/%comment%/来进行块注释,块中内容可以是单行或多行

变量内容扩展:将TLC变量通过%<>操作符将其内容扩展到输出流中

% assign input1 = 3
% assign input2 = 5
% warning %<input1> + %<input2> = %<input1 + input2>
输出:
Warning: 3 + 5 = 8

%<>不能嵌套使用,会报错:Expansion directives %<> cannot be nested

条件分支:if else要用end结束,expression的执行结果必须是整数

% if expression
% elseif expression
% else 
% endif

每个%if仅对应一个%else,如果出现多个%else会报错

开关分支:switch case语句

% switch expression
% case expression
% break
% default
% break
% endswitch

expression必须是一个能够使用==操作符来比较是否相等的数据类型

循环:包括%foreach, %roll, %for

  1. %foreach

    每个%foreach需要使用%endforeach终止;

    在循环体中可以使用%continue终止当前循环,从下一个循开始;或使用%break直接跳出循环

  2. %roll

    TLC中提供%roll循环方式是为了Simulink模块端口信号相关代码生成定义时使用。当模块的输入/输出信号维数是多维时,需要通过%roll对信号的每一维进行循环,使其生成的代码同时在Simulink环境中进行仿真时具有相同的维数

  3. %for

    使用方法与%foreach基本相同,并且加入了对于是否执行body以外部分进行roll的判断

    % for ident1 = const-exp1, const-exp2, ident2 = const-exp3
    	Code section 1
    	% body
    	Code section 2
    	% endbody
    	Code section 3
    	% endfor
    

    当const-exp2为非零值时,则Code section1/2/3所有的代码就会执行一次,并且ident2会接收const-exp3的值;而const-exp2为0时则仅执行Code section2段,其他段不执行,并且对其以ident1为循环变量进行循环,ident2为空值

在这里插入图片描述

文件流:使用%openfile创建文件流缓存或打开一个文件,%selectfile选中或激活一个存在的文件流缓存或文件,%closefile关闭一个文件流缓存或文件

% openfile streamId = "filename.ext"mode {open for writing}
% selectfile streamId{select an open file}
% closefile streamId{close an open file}

%openfile在打开文件时第二个参数mode,可以是a或者w,表示以“追加”或“重写”的方式创建文件或缓存块,默认以重写的方式写入streamId变量或其他表示的文件中。当所填写的文件名不存在时,使用streamId为名建立一个缓存块buffer进行后续操作。%openfile与%closefile之间的内容将被写入到缓存块buffer中作为变量保存起来,并且可以使用%将其展开到生成代码中。

StreamID所表示的参数有2个内建流变量:NULL_FILE(无输出)和STDOUT(使用终端输出文件流内容)。%selectfile同STDDOUT联合使用时,也可输出字符串内容到MATLAB的Command Window中

记录:相当于M语言或C语言的结构体类型,形式不同,是构成rtw文件的基本元素

%% 格式
record_item{Name Value}
% Name是字符串格式,按照字母顺序进行排序;
% Value可以是字符串也可以是数据类型,数据可以是scalar,向量或矩阵类型
  1. 创建一个记录(%createrecord)

    %createrecord NEW_RECORD{foo 1; SUB_RECORD{foo2}}
    % NEW_RECORD为新创建的记录名
    % {}内是其所属的子记录,同一层次的子记录之间使用:隔开,子记录再创建嵌套子记录时使用record_item{Name Value}方式
    %createrecord::NEW_RECORD{foo 1; SUB_RECORD{foo 2}}
    % ::表示全局变量标识符
    
  2. 追加记录(%addtorecord)

    %addtorecord OLD_RECORD NEW_FIELD_NAME NEW_FIELD_VAL
    OLD_RECORD:追加记录的对象
    NEW_FIELD_NAME:子记录的名字
    NEW_FIELD_VAL:子记录的值
    

    追加的结果在同一层次中按照首字母顺序排列,相邻两个子记录之间使用“;”分隔

  3. 合并记录(%mergerecord)

    %mergerecord OLD_RECORD NEW_RECORD
    合并的结果存在OLD_RECORD, NEW_RECORD内容不变
    

    当新旧两个记录中同样层次下存在相同名的记录时,保留这项记录各自的值不合并

  4. 拷贝记录(%copyrecord)

    %copyrecord NEW_RECORD OLD_RECORD
    OLD_RECORD:既存的记录
    NEW_RECORD:是OLD_RECORD的一份拷贝
    
  5. 删除记录(%undef)

    %undef var
    var:表示一个TLC变量,一个记录名或一个记录中的域的名字
    

    若要删除记录中的一个域成员,使用%with进行范围指定,在此范围内进行变量的删除

    %% example
    %createrecord NEW_RECORD{foo 1; SUB_RECORD{foo 2}}
    %with NEW_RECORD
    %undef foo
    %endwith
    %warning NEW_RECORD = %<NEW_RECORD>
    结果
    Warning : NEW_RECORD = {SUB_RECORD{foo 2}}
    直接使用“.”操作符删除记录的域会造成语法错误
    

变量的清除:%undef + TLC变量名即可删除变量

语句换行连接:C语言换行连接符“\”;MATLAB换行连接符“…”

字符串中使用换行连接符是非法的

访问范围:使用%assign所建立的是局部变量,如果定义在TLC脚本,只有此脚本里的语句可以访问;如果定义在函数里,只有此函数能访问该变量,如果定义在for循环语句内部,访问范围也只在这个语句块内部;“::”为TLC全局变量标识符

%with/%endwith命令可以锁定记录数据类型的范围,方便其内部TLC语句以子记录的名字方式直接访问其值,无须从最上层记录逐层域访问

%createrecord rec{field1 1 field2 2 field3 3}
%with rec
	%warning field1 = %<field1>
%endwith
%warning rec.field1 = %<rec.field1>

输入文件控制(%include string和%addincludepath string)

%include string:在搜索路径下寻找为string的文件,并在%include语句出现的地方将此文件内容内联展开

%addincludepath string:string是绝对路径或相对路径,%addincludepath将这个路径添加到TLC的搜索路径中,以便出现%include语句时搜索其包含的文件

TLC搜索路径的顺序

当前路径

所有的%addincludepath添加的路径,对于多个%addincludepath依照从下到上搜索路径

命令行中通过-I命令添加的路径

输出格式控制:使用%realformat控制输出实变量所显示的格式

指定模块生成代码的语言种类(%implements)

%implements "Block-Type" "Language"

断言:%assert

%assert expression
expression结果为TLC_FALSE时,TLC将进行堆栈追踪
开启TLC断言功能Configuration Parameter->Code Generation->Debug->Enable TLC assertion

函数:使用%function为开头定义函数原型,以%endfunction为终止符结束函数体

%function name(optional-arguments) void
%return
%endfunction
name表示函数名,optional-arguments表示函数的参数列表,void表示函数没有返回值,也可为Output表示有返回值,此时函数体中需要%return命令返回变量作为函数的输出

当在“%<>”中使用“>”,“>=”和“>>”之类带有“>”符号的操作符时,不能直接使用,需要前面加一个\以进行转义

TLC内建函数(全部都使用大写字母书写)

CAST("DataType", variablename) % 数据类型转换,DataType表示variablename转换的操作数
EXISTS(Var) % 变量的存在性,Var是一个变量名或一个记录的参数,返回值为Boolean型
FILE_EXISTS(expr) % 文件存在性判断,expr表示文件名的字符串
% 记录的域操作,%ISFIELD,%GETFIELD,%SETFIELD,%REMOVEFIELD函数都是与记录的域相关的内建函数;
通过%ISFIELD判断某个字符串表示的参数名是否为记录的域,
通过%SETFIELD和%GETFIELD设置/获取记录中参数的值,
通过%REMOVEFIELD删除
通过%FIELDNAMES函数可以查询记录中包含的内一层的记录名
ISEQUAL(expr1, expr2) % 判断两个变量是否相等,表达式运算的值大小相同即返回TLC_TRUE,否则返回TLC_TRUE;expr1和expr2不是数据类型,二者变量类型和内容必须完全一样才返回TLC_TURE
ISEMPTY()% 判断变量是否为空,数据类型为字符串,向量(Vector),矩阵(Matrix)和记录Record
TYPE(expr) % 判断变量类型
WHITE_SPACE(expr) % 判断空格,当一个变量内仅仅包含空格,如\n,\t,\r等时返回1,否则返回0,此函数判断参数是否为全空格的函数
当调用没有返回值的MATLAB函数时使用%matlab命令,
调用有返回值的函数时用%FEVAL,对于有多个返回值的函数,TLC只能接收首个返回值
%matlab fun(agr)
%matlab disp("I love TLC")
%assign result = FEVAL(MATLAB-function-name, rhs1, rhs2,...rhs3,...) % MATLAB-function-name为MATLAB函数名,rhs为MATLAB函数的参数列表

TLC命令行

![TLC开关命令表](C:\Users\user\Desktop\matlabbj\读懂代码\Simulink仿真及代码生成技术入门到精通笔记\TLC开关命令表.png)tlc[switch1 expr1 switch2 expr2...]filename.tlc % switchn表示开关符号,exrl1表示开关参数,同一个开关符号出现多次,最后一个被认为是有效的

在这里插入图片描述

TLC调试方法

  1. Configuration Parameter->Code Generation->Debug->TLC process->Start TLC debugger when generating code

  2. ctrl+B启动代码生成编译过程

  3. 使用whos查看当前访问范围中存在的变量及变量的TLC数据类型,希望查看某个变量的值,使用print调试命令,print TYPE(变量名),观察此后的代码情况使用list命令将返回当前程序之后的10行代码信息;

    list 10,20:显示当前TLC文件的第10-20行代码;

    使用next命令或简易命令n或step命令可进行单步执行,next是同一层的单步执行,step是step in执行;

    断点设置通过TLC调试命令break或简易命令b,指定断点所在的文件及行数,文件全名及行数之间使用“:”分隔,如break my.tlc:14,输入cont命令全速运行即会停止在离开始运行语句最近的一处断点处

    清除断点序号使用clear 1,clear all(清除所有断点),可以使用Disable关闭断点,再次使用用Enable

  4. 调试模式下可以省略%直接使用TLC命令assign进行操作,其他调试命令不能在调试模式下使用。调试结束可以使用cont运行代码生成流程或输入quit命令退出调试模式;可使用held command查询命令的帮助

TLC文件的覆盖度

Configuration Parameter->Debug->TLC process->Start TLC coverage when generating code

TLC Profiler

Configuration Parameter->Debug->TLC process->Profile TLC

TLC Profiler可以在执行过程中收集TLC代码各个元素的执行时间,并汇总到HTML的报告中,更容易分析并找到代码生成过程中最花费时间的代码

尽量少地使用TLC函数EXISTS,其对与一个变量或域的存在性的确认是十分耗时的;

尽可能多地内联简单的TLC函数,对于少行数TLC代码将其直接内联在程序中比函数化省时

支持代码生成的S函数

C MEX S函数和Level 2 M S函数支持代码生成功能,该功能要求S函数有配套的TLC文件

带有参数的S函数首先从GUI上获取用户的输入作为参数,通过C语言的宏将GUI控件上的值读入S函数,再通过S函数的子方法mdlRTW将参数值写入到模型的rtw文件中,使得TLC文件能够获取这些参数的值,最终展开到生成代码中合适的位置。
在这里插入图片描述

  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Luish Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值