Simulink仿真入门到精通(十八) TLC语言

TLC(Target Language Compiler)是一种为转换为目标语言而存在的额解释性语言,其目的就是将模型中编译出来的rtw文件转换为目标代码(C/C++等)。与M语言类似,既可以写成脚本文件,也能够作为函数存在,都是解释性语言,更相似的是它们都提供具有强大功能的内建函数库。

18.1 TLC的作用

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

Simulink中提供了很多既有TLC文件,如果擅自修改可能导致Simulink Coder功能性错误,故Mathworks提倡用户尽量不要修改TLC。但是如果能熟练掌握TLC的运行机制和编写方法,不仅不会伤害SImulink的功能,还可以巧妙利用TLC语言实现更多的自动化代码生成功能。

18.2 TLC的语法

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

18.2.1 基本语法

  1. [text|%]*

    text表示字符串,将原原本本地展开到输出流中。在%<>之中的是TLC变量,通过%<>作用将变量的执行结果显示到输出流中。

  2. %keyword[arguement1,arguement2,...]

    %keyword表示TLC语言中的命令符,[arguement1,arguement2,...]则表示这个命令符所操作的参数。

如:

% assign Str = "Hello World"

 

%warning、%error、%trace命令可以将其后的变量或字符串的内容输出。

Simulink仿真入门到精通(十八) TLC语言_第1张图片

>> tlc text.tlc
Warning:  Simulink User

Simulink仿真入门到精通(十八) TLC语言_第2张图片

>> tlc text.tlc
Error:  Simulink User
Main program:
==> [00] text.tlc:(1)

错误使用 tlc_new
Error: Errors occurred - aborting


出错 tlc (line 88)
  tlc_new(varargin{:});

若用%trace命令代替%warning命令显示信息,只有在执行TLC文件时在最后增加-v或者-v1才能将%trace后的信息显示出来。

TLC语言有两个内建宏TLC_TRUE=1和TLC_FALSE=0,在TLC语言的编写中会经常用到。

18.2.2 常用指令

注释

单行注释:双百分号%%

多行注释:/% comment %/

变量内容扩展

即通过%<>操作符将其内容扩展到输出流中。

%%text.tlc
%assign input1 = 3
%assign input2 = 5
%warning % + % = %

 

>> tlc text.tlc
Warning:  3 + 5 = 8

注意:%<>不能嵌套使用。

条件分支

%if expression

%elseif expression

%else

%endif

例:

%%text.tlc
%assign var = 2
%if ISEQUAL(var,1)
    %warning evering is OK.
%else
    %warning var should be 1 but now there is something wrong.
%endif

 

>> tlc text.tlc
Warning:  var should be 1 but now there is something wrong.

在内建函数ISEQUAL中不需要使用%<>。

开关分支

%switch expression

%case expression

%break

%default

%break

%endswitch

每个%case分支后必须跟%break才能起到真正的选择作用,否则将执行下一个%case语句。

%%text.tlc
%assign data = [1,2,3,4,5]
%switch TYPE(data)
%case "Number"
%warning Type is Number.
%break
%case "String"
%warning Type is String.
%break
%case "Vector"
%warning Type is Vector.
%break
%case "Matrix"
%warning Type is Matrix.
%break
%endswitch

 

>> tlc text.tlc
Warning:  Type is Vector.

循环

含%foreach、%roll、%for 3种常用方式。

(1)%foreach

%foreach loopIdx = iterNum

xxxxx

%endforeach

上述语句将loopIdx作为循环体句柄变量控制循环进行,从0开始,每次增加1,一直循环到iterMum-1为止。每个%foreach需要使用%endforeach来终止。

在循环体中可以使用%continue终止当前循环进入下一个循环,或者使用%break直接跳出循环。

%%text.tlc
%assign data = [1,2,3,4,5]
%foreach idx = 5
    %if ISEQUAL(idx,1)
        %continue
    %elseif ISEQUAL(idx,4)
        %break
    %endif
    %warning data[%] = %[idx]>
%endforeach

 

>> tlc text.tlc
Warning:  data[0] = 1
Warning:  data[2] = 3
Warning:  data[3] = 4

(2)%roll

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

%roll

%endroll

例:y=2×u

/% roll normally used in block tlc files to roll the 
inport/outport/parameter to access each dimension of them. %/
/* % Block: % */
%assign rollVars = ["U", "Y"]
%roll sigIdx = RollRegions, lcv = RollThreshold, block,...
"Roller", rollVars
%assign y = LibBlockOutputSignal(0, "", lcv, sigIdx)
%assign u = LibBlockInputSignal(0, "", lcv, sigIdx)
% = % * 2;
%endroll

 

%assign rollVars = ["U", "Y", "P"]定义rollVars变量存储循环体所涉及的模块要素,U表示输入端口,Y表示输出端口,在带有参数的模块中,P代表模块的参数。rollVars将被传递给Roller,设置模块输入/输出或参数中每一维roll的结构体。

%roll sigIdx = RollRegions定义了循环体的循环变量sigIdx,RollRegions是自动计算出来的模块输入/输出或参数的维数向量,如20维输入信号的RollRegions为[0:19],sigIdx按照这个向量进行逐一循环。

lcv = RollThreshold中lcv是循环控制变量(loop control variable),从RollThreshold获取值,表示当信号维数小于此数值时不生成for循环语句,而逐条生成语句,只有信号或参数的维数大于等于此数值时才生成for循环。TLC全局变量RollThreshold的值可以在Configuration Parameter→Code Generation→Advanced parameters中的Loop unrolling threshold设定,默认值为5。

 

 

LibBlockOutputSignal(portIdx, ucv, lcv, sigIdx)函数包含4个参数,portIdx表示模块输入端口的索引号(对于使能或触发端口,可以使用字符串enable和trigger获取),ucv通常为空,lcv和sigIdx同前面定义。该函数使用TLC库函数获取模块的输入/输出的参数中第sigIdx维所对应的变量,再通过% = % * %;进行代码生成的变量展开。

在循环体的结尾,使用%endroll作为终止符号。

(3)for

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

%for ident1 = const-exp1, const-exp2, ident2 = const-exp3

    Code section1

    %body

    Code section2

    %endbody

    Code section3

%endfor

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

%%text.tlc
%for idx = 3, 0, str = "yes"
   %warning OK?
    %body
         %warning Answer is % .
    %endbody
   %warning Over

%endfor
>> tlc text.tlc
Warning:  Answer is  .
Warning:  Answer is  .
Warning:  Answer is  .
%%text.tlc
%for idx = 3, 1, str = "yes"
   %warning OK?
    %body
         %warning Answer is % .
    %endbody
   %warning Over

%endfor
>> tlc text.tlc
Warning:  OK?
Warning:  Answer is yes .
Warning:  Over

文件流

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

%openfile streamId = "filename.txt" mode {open for writing}

%selectfile streanId {select an open file}

%closefile streamId {close an open file}

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

%%text.tlc
%openfile buffer = "my_flow_control.txt"
This is the first time flow control is used. 
%closefile buffer
>> tlc text.tlc

Simulink仿真入门到精通(十八) TLC语言_第3张图片

 

 

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

%%text.tlc
%selectfile STDOUT
text to be placed in the 'buffer' variable.
>> tlc text.tlc
text to be placed in the 'buffer' variable.

记录

TLC记录相当于M语言或C语言中的结构体类型,但形式不同,是构成rtw文件的基本元素,格式为record_item{Name Value}。Name是字符串格式,按照字母顺序进行排列;Value既可以是字符串也可以是数据类型,这个数据可以是scalar、向量或矩阵类型。

(1)创建一个新纪录

使用%createrecord命令创建一个新纪录。

%createrecord NEW_RECORD {foo 1;SUB_RECORD {foo 2}}

NEW_RECORD为新创建的纪录名,{ }内是其所属的子纪录。用一层次的子纪录使用";"隔开,子纪录再创建嵌套子纪录时使用record_item {Name Value}方式。

可以通过最上层记录名访问其子纪录内容。

%assign var1 = NEW_RECORD.foo

%assign var2 = NEW_RECORD.SUB_RECORD.foo

也可以创建具有全局访问权限的纪录(::表示全局标量标识符)

%createrecord::NEW_RECORD {foo 1;SUB_RECORD {foo 2}}

(2)追加纪录

使用%addtorecord命令向已经存在的额记录中追加新的子纪录。

%addtorecord OLD_RECORD NEW_FIELD_NAME NEW_FIELD_VALUE

3个参数,第一个参数为追加纪录的对象,第2个和第3个为子纪录的名字和值。

%%text.tlc
%createrecord NEW_RECORD {foo 1;SUB_RECORD {foo 2}}
%addtorecord NEW_RECORD str "I love Simulink"
%warning %
>> tlc text.tlc
Warning:  { SUB_RECORD { foo 2 }; foo 1; str "I love Simulink" }

(3)合并纪录

使用%mergerecord命令合并既存的两个纪录。

%mergerecord OLD_RECORD NEW_RECORD

合并后的内容保存在第一个参数中,第二个参数的值不变。

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

%%text.tlc
%createrecord NEW_RECORD {foo 1;SUB_RECORD {foo 2}}
%createrecord NEW_RECORD2 {str "I love Simulink"} %mergerecord NEW_RECORD NEW_RECORD2 %warning NEW_RECORD = % NEW_RECORD2 = % %% another demo
%createrecord NEW_RECORD {foo 1;SUB_RECORD {foo 2}}
%createrecord NEW_RECORD2 {foo 12} %mergerecord NEW_RECORD NEW_RECORD2 %warning NEW_RECORD = % NEW_RECORD2 = %

 

Warning:  { SUB_RECORD { foo 2 }; foo 1; str "I love Simulink" }
>> tlc text.tlc
Warning:  NEW_RECORD = { SUB_RECORD { foo 2 }; foo 1; str "I love Simulink" } NEW_RECORD2 = { str "I love Simulink" }
Warning:  NEW_RECORD = { SUB_RECORD { foo 2 }; foo 1 } NEW_RECORD2 = { foo 12 }

(4)拷贝纪录

使用%copyrecord命令进行纪录拷贝。

%copyrecord NEW_RECORD OLD_RECORD

OLD_RECORD是一个既存的纪录,NEW_RECORD则是OLD_RECORD的一份拷贝。

%%text.tlc
%createrecord NEW_RECORD {foo 1;SUB_RECORD {foo 2}}
%copyrecord NEW_RECORD2 NEW_RECORD
%warning NEW_RECORD = % NEW_RECORD2 = %
>> tlc text.tlc
Warning:  NEW_RECORD = { SUB_RECORD { foo 2 }; foo 1 } NEW_RECORD2 = { SUB_RECORD { foo 2 }; foo 1 }

(5)删除纪录

使用%undef命令删除记录中的域或者整个纪录。

%undef var

var表示一个TLC变量、一个记录名或一个纪录中的域的名字。

要删除一个域成员,可以借助%with进行范围指定。

%%text.tlc
%createrecord NEW_RECORD {foo 1;SUB_RECORD {foo 2}}
%with NEW_RECORD
%undef foo
%endwith
%warning NEW_RECORD = % 
>> tlc text.tlc
Warning:  NEW_RECORD = { SUB_RECORD { foo 2 } } 

变量清除

使用%under命令可以删除TLC变量。

%assign data = [1,2,3,4,5]
%undef data
%foreach idx = 5
    %warning data[%] = %[idx]>
%endforeach

%% error will occur because data is deleted.

 

>> tlc text.tlc
错误使用 tlc_new
Error: File: text.tlc Line: 5 Column: 31
Undefined identifier data
出错 tlc (line 88)
  tlc_new(varargin{:});

语句换行连接

换行符有两种,C语言的“\”和M语言的“...”。

%%text.tlc
%createrecord NEW_RECORD1...
    {foo 1;SUB_RECORD {foo 2}}
%warning NEW_RECORD1 = % 
%createrecord NEW_RECORD2\
    {foo 1;SUB_RECORD {foo 2}}
%warning NEW_RECORD2 = % 

 

>> tlc text.tlc
Warning:  NEW_RECORD1 = { SUB_RECORD { foo 2 }; foo 1 } 
Warning:  NEW_RECORD2 = { SUB_RECORD { foo 2 }; foo 1 }

访问范围

使用%assign str = "I Love Simulink"建立的string型变量str是局部变量,如果定义在TLC脚本中,只有在此脚本内的语句可以访问;如果是定义在函数里,仅此函数内能访问该变量;特别地,如果变量定义在for等循环语句块内部,只有在这个语句块内部能够访问。

%%text.tlc
%assign idx_i = "original string"
%assign data = [[1, "good"];[3, 4.5F]]
%foreach idx_i = 2
    %foreach idx_j = 2
        %warning The element of data[%][%] is ...
%[idx_i][idx_j]>
    %endforeach
%endforeach
%warning The original is %
>> tlc text.tlc
Warning:  The element of data[0][0] is 1
Warning:  The element of data[0][1] is good
Warning:  The element of data[1][0] is 3
Warning:  The element of data[1][1] is 4.5E+0F
Warning:  The original is original string

"::"为全局变量标识符。

%assign::str = "I Love Simulink"

输入文件控制

输入文件控制包括两种方式:%include string和%addincludepath string

%include string将在搜索路径下寻找名为string的文件,并在%include语句出现的地方将此文件的内容内联展开,类似于C语言中的#include。

%addincludepath string中string是一个绝对路径或相对路径,%addincludepath将这个路径添加到TLC的搜索路径中,以便出现%include语句时搜索器包含的文件,类似于MATLAB中的addpath命令。

TLC搜索路径依照如下顺序:

  1. 当前路径;
  2. 所有的%addincludepath添加的路径,对于多个%addincludepath,依照从下到上的搜索顺序;
  3. 命令行中通过-I命令添加的路径。
%addincludepath "C:\\folder1\\folder2"  %%添加一个绝对路径
%addincludepath "\\folder2"  %%添加一个相对路径

输出格式控制

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

如使用16位精度的指数显示。

%realformat "EXPONENTIAL"

 

 

或者无精度损失和最小字符数格式(为S函数提供生成代码功能的模块级TLC文件就使用这种格式)

%realformat "CONCISE"

 

例:

%%text.tlc
%createrecord NEW_RECORD {foo 100.0;SUB_RECORD {foo 2}}
%realformat "EXPONENTIAL"
%warning %
%realformat "CONCISE"
%warning %

 

>> tlc text.tlc
Warning:  1.0E+2
Warning:  100.0

指定模块生成代码的语言类型

使用%language命令指定该模块生成代码的语种。如果自定义支持嵌入式代码生成的模块及其TLC文件,那么在TLC文件中就可以使用%language C来指定语言类型为C语言。

对于Simulink模块的TLC文件,其中必须包含%implements指令。

%implements "Block-Type" "Language"

Block-Type是指模块的S函数名,TLC文件也是此名字。Language表示生成的目标代码的语言类型。

对于自定义的为了生成嵌入式C语言的MCU芯片驱动中断控制器模块,其TLC文件开头必须包含这样一个命令:

%implements Interrupt "C"

紧接此句的是%function的函数定义,实现S函数代码生成的具体功能。

另外,%generatefile提供了一个匹配关系,将Simulink模块和TLC文件联系起来。

%generatefile "Type" "blockwise.tlc"

Type为rtw文件中模块的记录中Type参数的值,也即模块的blocktype属性,如:%generatefile "Sin" "sin_wave.tlc"。

断言

使用%assert命令为TLC断言。

%assert expression

当expression结果为TLC_FALSE时,TLC将进行堆栈追踪。

为了开启TLC的断言功能,必须在Configuration Parameter中勾选Enable TLC assertion。

函数

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

%function name(optional-arguments) void

%return

%endfunction

%function LibGetMathConstant(ConstName,ioTypeId) void
  %assign constInfo = SLibGetMathConstantInfo(ConstName,ioTypeId)
  %if !ISEMPTY(constInfo)
    %return constInfo.Expr
  %else
    %return ""
  %endif
%endfunction

 

18.2.3 变量类型

TLC语言使用的变量类型和MATLAB变量所使用的内建类型有所不同。在TLC语言中不仅是数据的类型,甚至数据的组织方式都被作为一个单独的类型,如Matrix、Vector。Range等。

数据类型名(简写) 表现形式举例 说明
Boolean(B) 0==0 返回值为TLC_TRUE或TLC_FALSE,由逻辑操作返回
Number(N) 100 整型数
Real(D)s 3.14159 浮点数
Real32(F)s 3.14159F 32位浮点数
Complex(C) 1.0+2.0i 64位双精度浮点数
Complex32(C32) 10.F+2.0Fi 32位单精度浮点数
Gaussion(G) 1+2i 32位整型复数
Unsigned(U) 100U 32位无符号整数
Unsigned Gaussion(UG) 1U+2Ui 32位无符号整型复数
String "I Love MATLAB" 包含在双引号中的字符串
Identifier abc 此类型仅出现在rtw记录中,不可直接在TLC表达式中使用。如果希望比较其内容,可直接与String类型比较,Identifer将自动转换为String类型
File

%openfile out="xx.c"

%openfile buffer

使用%openfile打开的字符串缓冲或文件
Function %function my_func ... TLC的函数类型,需要使用%endfunction结束
Range [1:10] 表示一组整数序列,如RollRegions使用在Roll循环体中表示循环变量遍历的值
Vector [1,2.0F,"good"] 向量类型,每个元素可以是TLC的内建类型,但不能是Vector或Matrix
Matrix %assign a=[[1,"good"];[3,4.5F]] 矩阵类型,矩阵中每个元素类型可以不同,但是不能为Vector或Matrix
Scope system {...} 范围类型,如rtw中的CompiledModel、block记录的范围
Subsystem 子系统标示符,作为语句扩展的内容
Special FILE_EXISTS 特殊内建类型如FILE_EXISTS

18.2.4 操作符和表达式

::variable 全局变量,当出现在函数中时,告诉函数该变量的访问权限是全局的,不适用函数的局部访问权限
expr[indx] 数组或矩阵的下标索引访问方式,indx必须是0~(N-1),N为数组长度或矩阵某一维的长度
func([expr[,expr]...]) 函数调用,func为函数名,expr为函数的参数列表
expr.expr 域访问符,第一个expr为纪录类型,第2个expr为其内部的一个参数名
(expr) 括号,括号内的表达式优先度高
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   

 

你可能感兴趣的:(Simulink仿真入门到精通(十八) TLC语言)