设备树编译器DTC中几个关于词法分析器和语法分析器中使用的数据结构

下面是DTS源文件布局的一个非常粗略的概述:

sourcefile : versioninfo plugindecl list_of_memreserve devicetree

memreserve: label ‘memreserve’ ADDR ADDR ‘;’
| label ‘memreserve’ ADDR ‘-’ ADDR ‘;’

devicetree: ‘/’nodedef

versioninfo: ‘/’ ‘dts-v1’ ‘/’ ‘;’

plugindecl: ‘/’ ‘plugin’ ‘/’ ‘;’
| /* empty */

nodedef: ‘{’ list_of_property list_of_subnode ‘}’ ‘;’

property: label PROPNAME ‘=’ propdata ‘;’

propdata: STRING
| ‘<’ list_of_cells ‘>’
| ‘[’ list_of_bytes ‘]’

subnode: label nodename nodedef

这种结构形成了一个以初始节点为根的节点和属性的层次布局:

/{
}

支持经典C和C++类型的注释。
源文件可以使用下面的语法包含:

/include/ “filename”

属性
属性是有名称的,可能是标签,值。每个值都是下面中的一个:
a、一个以null结尾的类似C的字符串
b、一个32位的数字值
c、一个32位值的列表
d、一个字节序列
下面是属性定义的一些示例:
a、一个包含0结尾的字符串属性
property1 = “string value”;
b、一个包含一个32位十六进制数字的属性
property2 = <1234abcd>;
c、一个包含3个32位十六进制数字的属性
property3 = <12345678 12345678 deadbeef>;
d、一个包含任意字节数组的属性
property4 = [0a 0b 0c 0d de ea ad be ef];
节点可以包含子节点以获取层次结构。
例如:
一个名为childnode的子节点,它的单位名字是childnode at address。它有一个名为childprop的字符串属性。

childnode@address{
childprop = “hello\n”;
};

默认情况下所有数字值是十六进制。可以使用前缀d#指示10进制,b#指示二进制,o#指示八进制。
字符串支持C中常见的转义序列:”\n”,”\t”,”\r”,”(octal value)”,”\x(hex value)”。

标签和引用
标签可以被应用到节点和属性。标签出现在一个节点名字之前,且使用&引用:&label。绝对节点路径名也允许节点的引用。
在下面的示例中,节点的标签名是”mpic”,且它被引用:

mpic: interrupt-controller@40000{
...
};

ethernet-pht@3{
interrupt-parent = <&mpic>;
...
};

在属性中,标签可以出现在任何值的之前或之后:

randomnode{
prop: string = data:”mystring\n”data_end:;
...
};

下面是设备树源文件的一段示例:

/dts-v1/;

include "am4372.dtsi"

include <dt-bindings/pinctrl/am43xx.h>

include <dt-bindings/gpio/gpio.h>

include <dt-bindings/pwm/pwm.h>

include <dt-bindings/sound/tlv320aic31xx-micbias.h>

/ {
model = "TI AM43x EPOS EVM";
compatible = "ti,am43x-epos-evm","ti,am438x","ti,am43";

aliases {
display0 = &lcd0;
};

chosen {
stdout-path = &uart0;
};

vmmcsd_fixed: fixedregulator-sd {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-high;
};

vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};

lcd0: display {
compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
label = "lcd";

backlight = <&lcd_bl>;

port {
lcd_in: endpoint {
remote-endpoint = <&dpi_out>;
};
};
};
};


上图中标识出了节点,属性和标签。
节点由节点的名称和单位地址,节点的属性,子节点,父节点和兄弟节点组成;属性有属性名和属性值;属性值可以是字符串,字节字符串,一个标签的引用或32位的值;标签以冒号结尾。
下面是DTC中关于这几种数据抽象出的数据结构:
数据类型枚举类:

enum markertype {
TYPE_NONE,
REF_PHANDLE,
REF_PATH,
LABEL,
TYPE_UINT8,
TYPE_UINT16,
TYPE_UINT32,
TYPE_UINT64,
TYPE_STRING,
};

标记结构体:

struct marker {
enum markertype type;
unsigned int offset;
char *ref;
struct marker *next;
};

数据结构体:

struct data {
unsigned int len;
char *val;
struct marker *markers;
};

标签结构体:

struct label {
bool deleted;
char *label;
struct label *next;
};

总线类型结构体:

struct bus_type {
const char *name;
};

属性结构体:

struct property {
bool deleted;
char *name;
struct data val;

struct property *next;

struct label *labels;
struct srcpos *srcpos;
};

节点结构体:

struct node {
bool deleted;
char *name;
struct property *proplist;
struct node *children;

struct node *parent;
struct node *next_sibling;

char *fullpath;
int basenamelen;

cell_t phandle;
int addr_cells, size_cells;

struct label *labels;
const struct bus_type *bus;
struct srcpos *srcpos;

bool omit_if_unused, is_referenced;
};

保留内存信息结构体:

struct reserve_info {
uint64_t address, size;

struct reserve_info *next;

struct label *labels;
};

设备树结构体:

struct dt_info {
unsigned int dtsflags;
struct reserve_info *reservelist;
uint32_t boot_cpuid_phys;
struct node dt; / the device tree */
const char outname; / filename being written to, "-" for stdout */
};

在词法分析和语法分析中,匹配到规则时会调用上面这些相关结构体的操作函数,最后将dts文件解析为dt_info的信息结构。

/************************************************************************************************************/
对DTC的分析还在学习中,后续继续分享

posted @ 2025-03-31 21:26  xiaobing3314  阅读(58)  评论(0)    收藏  举报