南京观海微电子----时序图绘制工具

发布时间:2024年01月14日

Wavedrom 是一款功能强大且简单易用的文本转图表工具,被广泛应用于生成时序图、波形图等交互式波形。其特点在于使用简单的文本语法,使得开发人员能够以可视化的方式表示数字信号和时间序列数据。Wavedrom 的优势在于其高度灵活性和可扩展性,使用户能够快速绘制复杂的波形和图表,并轻松与其他文档和代码进行整合。

Wavedrom 的基本语法相对简单,以 JSON 对象或简洁的文本描述波形和时序信息。开发人员只需编写简短的描述,即可生成直观的波形图。通过使用不同的标记和元素,用户可以定义时序图中的信号波形、时钟周期、状态转换等内容。Wavedrom 支持自定义样式和布局,用户可以根据需求美化波形图,增加标签和注释以增强可读性。

时序图是 Wavedrom 最常见的用途之一,通过 Wavedrom 绘制的时序图可以清晰地展示数字信号和数据的传输过程。例如,在硬件设计中,时序图可以用于描述寄存器读写、信号传输和时钟脉冲的情况,从而帮助开发人员更好地理解和分析系统的工作状态。

值得一提的是,Wavedrom 不仅可以独立使用,还可以与 Markdown 等文档格式无缝整合。通过将 Wavedrom 图表代码嵌入文档中,开发人员可以直接在文档中呈现交互式的波形图,提升文档的可读性和交互性。

总体来说,Wavedrom 是一个强大而简便的文本转图表工具,适用于各种应用场景,如硬件设计、软件开发、文档编写等。其简单的语法和可视化的输出,为开发人员提供了一个高效、直观的工具,帮助他们更好地表达和展示数字信号和时间序列数据。

用法和示例

WaveDrom 是一个基于 JavaScript 的应用程序。WaveJSON 是一种描述数字时序图的格式。WaveDrom 可以直接在浏览器中渲染这些图表。"signal"元素是 WaveLane 的数组。每个 WaveLane 都有两个必填字段:"name"和"wave"。

WaveDrom 是一个强大的工具,可用于可视化数字信号和时序数据。通过使用 WaveJSON 格式来描述信号波形,用户可以轻松地定义时序图的各个部分,包括信号波形的名称、周期和状态。WaveDrom 支持多个 WaveLane,可以同时显示多个信号波形,从而实现更复杂的时序图表。

"wave"字段是 WaveLane 的关键部分,用于定义信号波形。它由一系列字符组成,包括数字 0 和 1,代表数字信号的高和低电平,以及".",代表未定义或无效状态。此外,WaveDrom 还支持其他特殊字符,如"p"代表时钟周期,"n"代表一个时钟周期内的半个周期,"|"用于分隔不同的时钟周期。

通过将这些 WaveLane 组合成一个"signal"数组,并为每个 WaveLane 指定名称和波形描述,用户可以创建详细且直观的数字时序图。WaveDrom 渲染引擎会将这些描述解析并在浏览器中实时绘制出时序图形。

总的来说,WaveDrom 提供了一种简单但强大的方式,通过 WaveJSON 格式和 WaveLane 的组织,使用户能够在浏览器中生成各种数字时序图。它在硬件设计、嵌入式系统开发、通信协议分析等领域中有着广泛的应用,帮助开发人员更好地理解和分析数字信号的行为和传输过程。

信号

从一个简单的例子开始。下面的代码将创建一个名为"Alfa"的 1 位信号,并随时间改变其状态。

{?"signal":?[{?"name":?"Alfa",?"wave":?"01.zx=ud.23.456789"?}]?}

在"wave"字符串中,每个字符代表一个时间周期。符号"."将前一个状态延续一个周期。现在,让我们看一下它的图示:

图片

"Alfa" 1位信号

时钟

数字时钟是一种特殊类型的信号。它在每个时间周期内变化两次,可以具有正极性或负极性。此外,它还可以在工作边沿上带有可选的标记。时钟的各个块可以与其他信号状态混合,以创建时钟门控效果。下面是代码和生成的图示:

{?"signal":?[
??{?"name":?"pclk",?"wave":?"p......."?},
??{?"name":?"Pclk",?"wave":?"P......."?},
??{?"name":?"nclk",?"wave":?"n......."?},
??{?"name":?"Nclk",?"wave":?"N......."?},
??{},
??{?"name":?"clk0",?"wave":?"phnlPHNL"?},
??{?"name":?"clk1",?"wave":?"xhlhLHl."?},
??{?"name":?"clk2",?"wave":?"hpHplnLn"?},
??{?"name":?"clk3",?"wave":?"nhNhplPl"?},
??{?"name":?"clk4",?"wave":?"xlh.L.Hx"?},
]}

渲染后的时钟图示如下:

图片

时钟信号

合在一起

在典型的时序图中,我们通常会包含时钟信号和其他信号(线路)。对于多位信号,我们可以从"data"数组中获取相应的标签。

下面是一个例子,展示了一个包含时钟信号、多位信号和单位信号的典型时序图:

{?"signal":?[
??{?"name":?"clk",?"wave":?"P......"?},
??{?"name":?"bus",?"wave":?"x.==.=x",?"data":?["head",?"body",?"tail",?"data"]?},
??{?"name":?"wire",?"wave":?"0.1..0."?}
]}

在这个例子中,我们有三个信号:"clk"代表时钟信号,"bus"代表多位信号,"wire"代表单位信号。

  • 时钟信号"clk"用"P"表示,代表正极性的时钟边沿。

  • 多位信号"bus"用"x.==.=x"表示,其中"x"表示未定义的状态,"="表示稳定的高电平或低电平,"."表示未稳定状态。"data"数组包含多位信号的标签,分别是:"head"、"body"、"tail"和"data"。

  • 单位信号"wire"用"0.1..0."表示,表示在时间周期内信号从低电平切换到高电平再切换回低电平。

渲染后的时序图如下:

图片

典型时序信号

空白和间隙

在时序图中,我们有时需要添加间距和空白,以便更好地组织信号和使时序图更易于阅读。下面是一个带有间距和空白的时序图示例:

{?"signal":?[
??{?"name":?"clk",?"wave":?"p.....|..."?},
??{?"name":?"Data",?"wave":?"x.345x|=.x",?"data":?["head",?"body",?"tail",?"data"]?},
??{?"name":?"Request",?"wave":?"0.1..0|1.0"?},
??{},
??{?"name":?"Acknowledge",?"wave":?"1.....|01."?}
]}

在这个例子中,我们添加了一些间距和空白,以便更好地分隔不同的信号。

  • "clk"信号用"p"表示,代表正极性时钟边沿,后面有 3 个间距".",然后是"|...",代表 3 个空白周期。

  • "Data"信号由"x"、"="、"."组成,数据数组"data"提供了多位信号各个部分的标签:"head"、"body"、"tail"和"data"。后面有一个间距"|",然后是"=.",代表一个空白周期后紧跟着一个稳定高电平。

  • "Request"信号由"0"、"1"、"."组成,代表低电平、高电平和未定义状态。后面有一个间距"|",然后是"1.0",代表一个高电平后紧跟着一个空白周期。

  • 接着有一个空白行,表示两个信号之间的空白。

  • 最后,"Acknowledge"信号由"1"、"."组成,后面有一个间距"|",然后是"01.",代表一个高电平后紧跟着一个低电平和一个空白周期。

渲染后的时序图如下:

图片

带间隙的时序图

在这个时序图中,我们可以看到信号之间的间距和空白,使得时序图更加整齐和易读。通过添加适当的间距和空白,我们可以更好地组织信号和时钟边沿,使时序图更具可视化效果。接下来,我们将继续探索 WaveDrom 的其他高级功能和实际应用,帮助您更好地运用这个强大的文本转图表工具。

分组

在时序图中,我们可以将 WaveLane 组合成具有名称的分组,分组表示为数组形式。['分组名称', {...}, {...}, ...] 数组的第一个条目是分组的名称。分组之间还可以嵌套。

下面是一个包含分组的时序图示例:

{?"signal":?[
??{?"name":?"clk",?"wave":?"p..Pp..P"?},
??["Master",
????["ctrl",
??????{?"name":?"write",?"wave":?"01.0...."?},
??????{?"name":?"read",?"wave":?"0...1..0"?}
????],
????{?"name":?"addr",?"wave":?"x3.x4..x",?"data":?"A1?A2"?},
????{?"name":?"wdata",?"wave":?"x3.x....",?"data":?"D1"?},
??],
??{},
??["Slave",
????["ctrl",
??????{?"name":?"ack",?"wave":?"x01x0.1x"?},
????],
????{?"name":?"rdata",?"wave":?"x.....4x",?"data":?"Q2"?},
??]
]}

在这个例子中,我们使用了分组来组织不同的信号,将它们放在名为"Master"和"Slave"的两个分组中。

  • "clk"信号用"p..Pp..P"表示,代表正极性时钟边沿和负极性时钟边沿。

  • "Master"分组包含了三个子信号,它们分别在名称为"ctrl"的子分组中,表示控制信号"write"和"read",以及名称为"addr"的信号,"data"数组提供了信号的标签。

  • 接着有一个空白行,表示两个分组之间的空白。

  • "Slave"分组包含了两个子信号,都在名称为"ctrl"的子分组中,表示控制信号"ack",以及名称为"rdata"的信号,"data"数组提供了信号的标签。

渲染后的时序图如下:

图片

分组时序图

在这个时序图中,我们可以看到不同分组内的信号在不同时间周期内的状态。使用分组可以更好地组织和显示复杂的时序图,帮助我们更好地理解和分析数字信号之间的时序关系。通过 WaveDrom 的强大功能,我们可以轻松地在时序图中添加分组,使其更具可视化效果和清晰度。

周期和相位

在时序图中,我们可以使用"period"和"phase"参数来调整每个 WaveLane 的周期和相位。

下面是一个 DDR 读取事务的时序图示例:

{?"signal":?[
??{?"name":?"CK",?"wave":?"P.......",?"period":?2?},
??{?"name":?"CMD",?"wave":?"x.3x=x4x=x=x=x=x",?"data":?"RAS?NOP?CAS?NOP?NOP?NOP?NOP",?"phase":?0.5?},
??{?"name":?"ADDR",?"wave":?"x.=x..=x........",?"data":?"ROW?COL",?"phase":?0.5?},
??{?"name":?"DQS",?"wave":?"z.......0.1010z."?},
??{?"name":?"DQ",?"wave":?"z.........5555z.",?"data":?"D0?D1?D2?D3"?}
]}

在这个例子中,我们使用"period"参数来设置时钟信号"CK"的周期为 2 个时间周期。这意味着时钟信号每隔 2 个时间周期变化一次。

同时,我们使用"phase"参数来调整信号"CMD"和"ADDR"的相位。相位的值为 0.5,表示信号的波形在时间轴上整体向右偏移了 0.5 个时间周期。这样做可以让信号在时钟边沿之前或之后发生状态变化。

"CMD"信号表示了 DDR 读取事务的命令序列,"ADDR"信号表示了地址序列。"data"数组提供了每个部分的标签。

"DQS"信号和"DQ"信号分别表示数据校验和数据信号。其中,"DQS"信号在时钟边沿之前有一个延迟,"DQ"信号在时钟边沿之后有一个延迟。

渲染后的时序图如下:

图片

DDR读时序

在这个时序图中,我们可以看到时钟信号"CK"每隔 2 个时间周期发生一次变化。"CMD"和"ADDR"信号的波形整体向右偏移了 0.5 个时间周期,以达到与时钟信号的相位差。"DQS"信号在时钟边沿之前有一个延迟,"DQ"信号在时钟边沿之后有一个延迟。

通过调整"period"和"phase"参数,我们可以更灵活地控制时序图中各个信号的周期和相位,从而更好地表达复杂的数字信号行为。WaveDrom 提供了丰富的功能,帮助我们创建详细和直观的数字时序图,用于硬件设计、嵌入式系统开发、通信协议分析等领域。

config{}属性

在时序图中,config{}属性用于控制渲染的不同方面。

hscale

config:{hscale:#}属性用于调整时序图的水平缩放比例。用户可以设置任何大于 0 的整数值。

下面是一个示例,展示了如何使用 config{hscale:#}属性来调整时序图的水平缩放比例:

{?"signal":?[
??{?"name":?"clk",?"wave":?"p...."?},
??{?"name":?"Data",?"wave":?"x345x",?"data":?["head",?"body",?"tail"]?},
??{?"name":?"Request",?"wave":?"01..0"?}
],
"config":?{?"hscale":?1?}
}

在这个例子中,我们使用 config{hscale:1}属性将水平缩放比例设置为 1。这意味着时序图将以原始比例进行渲染,每个时间周期占据一个单位宽度。

渲染后的时序图如下:

图片

水平比例1

图片

水平比例2

skin

在时序图中,我们可以使用 config:{skin:'...'}属性来选择WaveDrom 的皮肤样式[2]。该属性仅在页面上的第一个时序图中起作用。WaveDrom 编辑器包含两种标准皮肤:'default'和'narrow'。

head/foot

head:{...}和 foot:{...}属性用于定义时序图上方和下方的内容区域。可以在这些属性中添加文本或其他元素。

tick/tock

tick 属性可以添加与垂直标记对齐的时间线标签,而 tock 属性可以在垂直标记之间添加时间线标签。

text

text 属性用于添加标题或说明文本。

every

every 属性用于指定仅在每 N 个周期渲染一次标记和时间线标签。

下面是一个示例,展示了如何使用这些属性来定义一个时序图:

{?"signal":?[
??{?"name":?"clk",?"wave":?"p...."?},
??{?"name":?"Data",?"wave":?"x345x",?"data":?"a?b?c"?},
??{?"name":?"Request",?"wave":?"01..0"?}
],
"head":?{
??"text":?"WaveDrom?example",
??"tick":?0,
??"every":?2
},
"foot":?{
??"text":?"Figure?100",
??"tock":?9
}
}

在这个例子中,我们添加了头部(head)和底部(foot)的文本内容。头部文本设置为"WaveDrom example",并使用 tick 属性指定不添加时间线标签。每隔 2 个周期渲染一次标记和时间线标签。底部文本设置为"Figure 100",并使用 tock 属性在垂直标记之间添加时间线标签。

渲染后的时序图如下:

图片

属性示例

在 WaveDrom 中,head 和 foot 属性用于定义时序图上方和下方的文本内容,这些文本内容支持 SVG text 的所有属性。可以使用 JsonML 标记语言来表示 SVG 文本内容,并且可以使用一些预定义的样式来设置文本的字体大小和颜色。除此之外,还可以使用其他 SVG tspan 属性来自由地定制文本的样式。

下面是一个示例,展示了如何使用不同的样式来设置时序图头部和底部的文本内容:

{?"signal":?[
??{?"name":?"clk",?"wave":?"p.....PPPPp...."?},
??{?"name":?"dat",?"wave":?"x....2345x.....",?"data":?"a?b?c?d"?},
??{?"name":?"req",?"wave":?"0....1...0....."?}
],
"head":?{?"text":
??["tspan",
????["tspan",?{?"class":?"error?h1"?},?"error?"],
????["tspan",?{?"class":?"warning?h2"?},?"warning?"],
????["tspan",?{?"class":?"info?h3"?},?"info?"],
????["tspan",?{?"class":?"success?h4"?},?"success?"],
????["tspan",?{?"class":?"muted?h5"?},?"muted?"],
????["tspan",?{?"class":?"h6"?},?"h6?"],
????"default?",
????["tspan",?{?"fill":?"pink",?"font-weight":?"bold",?"font-style":?"italic"?},?"pink-bold-italic"]
??]
},
"foot":?{?"text":
??["tspan",?"E=mc",
????["tspan",?{?"dy":?"-5"?},?"2"],
????["tspan",?{?"dy":?"5"?},?".?"],
????["tspan",?{?"font-size":?"25"?},?"B?"],
????["tspan",?{?"text-decoration":?"overline"?},?"over?"],
????["tspan",?{?"text-decoration":?"underline"?},?"under?"],
????["tspan",?{?"baseline-shift":?"sub"?},?"sub?"],
????["tspan",?{?"baseline-shift":?"super"?},?"super?"]
??],?"tock":?-5
}
}

在这个例子中,我们使用 JsonML 标记语言来表示头部和底部的文本内容,并为每个文本段落设置了不同的样式。例如,我们使用了类名"h1"、"h2"、"h3"等来设置不同的字体大小。使用类名"error"、"warning"、"info"、"success"、"muted"等来设置不同的字体颜色样式。我们还可以使用其他 SVG tspan 属性来设置文本的斜体、粗体、填充颜色等。

渲染后的时序图如下:

图片

head/foot文本属性示例

箭头

曲线

在 WaveDrom 中,我们可以使用箭头和曲线来连接不同的信号,以表示它们之间的关联和数据传递。

以下是一些常用的箭头和曲线符号:

  • ~:普通曲线

  • -~:从左到右的曲线箭头

  • <~>:双向曲线箭头

  • <~>:双向曲线箭头

  • ~>:从左到右的直线箭头

  • -~>:从左到右的实心箭头

  • ~->:从右到左的实心箭头

下面是一个示例,展示了如何使用箭头和曲线来连接不同的信号:

{?"signal":?[
??{?"name":?"A",?"wave":?"01........0....",?"node":?".a........j"?},
??{?"name":?"B",?"wave":?"0.1.......0.1..",?"node":?"..b.......i"?},
??{?"name":?"C",?"wave":?"0..1....0...1..",?"node":?"...c....h.."?},
??{?"name":?"D",?"wave":?"0...1..0.....1.",?"node":?"....d..g..."?},
??{?"name":?"E",?"wave":?"0....10.......1",?"node":?".....ef...."?}
],
"edge":?[
??"a~b?t1",?"c-~a?t2",?"c-~>d?time?3",?"d~-e",
??"e~>f",?"f->g",?"g-~>h",?"h~>i?some?text",?"h~->j"
]
}

渲染后的时序图如下:

图片

箭头和曲线

折线

在 WaveDrom 中,我们还可以使用尖锐的线条符号来表示不同信号之间的连接关系。这些尖锐的线条符号可以更直观地展示信号之间的交互和数据传递。

以下是一些常用的尖锐线条符号:

  • -:直线连接

  • -|:从左到右的尖锐连接

  • |->:从右到左的尖锐连接

  • <->:双向尖锐连接

  • <-|>:从左到右的双向尖锐连接

  • |-|:从左到右的尖锐连接(包含短横线)

下面是一个示例,展示了如何使用尖锐线条来连接不同的信号:

{?"signal":?[
??{?"name":?"A",?"wave":?"01..0..",?"node":?".a..e.."?},
??{?"name":?"B",?"wave":?"0.1..0.",?"node":?"..b..d.",?"phase":?0.5?},
??{?"name":?"C",?"wave":?"0..1..0",?"node":?"...c..f"?},
??{?"node":?"...g..h"?},
??{?"node":?"...I..J",?"phase":?0.5?},
??{?"name":?"D",?"wave":?"0..1..0",?"phase":?0.5?}
],
"edge":?[
??"b-|a?t1",?"a-|c?t2",?"b-|-c?t3",?"c-|->e?t4",?"e-|>f?more?text",
??"e|->d?t6",?"c-g",?"f-h",?"g<->h?3?ms",?"I+J?5?ms"
]
}

在这个例子中,我们有 6 个信号(A、B、C、D)和 4 个连接节点(e、g、h、I、J),它们之间通过尖锐线条连接起来。每个信号都有相应的波形图,而尖锐线条则通过edge属性来定义连接关系。

例如,b-|a t1表示从信号 B 到信号 A 的从左到右的尖锐连接,并在连接上方添加了文本标签"t1"。c-|->e t4表示从信号 C 到节点 e 的从左到右的尖锐连接,并在连接上方添加了文本标签"t4"。

渲染后的时序图如下:

图片

箭头和折线

一些代码

在 WaveDrom 中,我们可以使用 JavaScript 代码来生成复杂的时序图。这些代码可以用来生成特定的信号和波形,以及自定义时序图的展示效果。

以下是一个示例代码,展示了如何使用 JavaScript 代码生成一个特定的时序图:

(function?(bits,?ticks)?{
??var?i,?t,?gray,?state,?data?=?[],?arr?=?[];
??for?(i?=?0;?i?<?bits;?i++)?{
????arr.push({name:?i?+?'',?wave:?''});
????state?=?1;
????for?(t?=?0;?t?<?ticks;?t++)?{
??????data.push(t?+?'');
??????gray?=?(((t?>>?1)?^?t)?>>?i)?&?1;
??????arr[i].wave?+=?(gray?===?state)???'.'?:?gray?+?'';
??????state?=?gray;
????}
??}
??arr.unshift('gray');
??return?{signal:?[
????{name:?'bin',?wave:?'='.repeat(ticks),?data:?data},?arr
??]};
})(5,?16)

在这个例子中,我们使用了一个自执行函数来生成一个包含 5 个信号的时序图。每个信号的波形图都是根据格雷码(Gray code)生成的,其中 bits 参数表示信号的位数,ticks 参数表示时间周期数。代码使用循环来生成信号的波形图,并将生成的数据存储在 data 数组中。

最终的时序图包含 6 个信号,其中一个是用来表示二进制计数的信号(bin),其波形图是一个等号序列。其他 5 个信号的波形图是根据格雷码生成的,分别对应 0 位、1 位、2 位、3 位和 4 位格雷码的波形。

渲染后的时序图如下:

图片

js代码生成时序图

文章来源:https://blog.csdn.net/m0_72563973/article/details/135580067
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。