碎碎念:
没想到上一篇发出去,前几个小时竟然基本没人看,是我写得太晦涩了吗,这篇介绍个简单但是相当好用的软件WaveDrom,可以非常方便的绘制时序图,简直是数字人的福音啦!
本文将从安装开始,详细介绍涉及到的语法等内容,读者可以收藏起来随时查阅。
P.S. 照这个速度,也不知道多久能把Basic Verilog库中的模块学习完毕哇_(:з)∠)_(已经忘记了是这周第几躺了)。
目录
2.3 将时钟与信号结合(Putting all together)
2.7 其他属性配置(The config{} property)
1 软件安装
官网地址:WaveDrom - Digital timing diagram everywhere
软件本身分为离线版和在线版,由于在线版并不需要安装,因此这里主要介绍离线版的安装过程,与一般软件需要安装包不同,这个软件下载下来的就是整个程序,直接打开对应可执行文件就可以直接运行。
在官网点击左下角的“Download editor”即可打开下载界面:
选择自己系统对应的版本就可以啦,这里我选择Windows 64位版本的,点击右侧按钮就可以下载软件了。(我这里用了edge的插件,所以看起来和原始Github按钮不一样,大家可以忽略)
打开压缩包中,点击wavedrom-editor.exe,即可直接运行程序。
可以将文件解压到自己常用的安装目录下,然后将wavedrom-editor.exe发送快捷方式到桌面,方便打开。
当出现这样的界面,就说明已经可以成功运行啦,下面开始对绘图功能的教程。
2 绘图教程
WaveDrom提供了官方教程,本绘图教程基于官方教程展开(比官方教程详细多了)。
想要直接进行查阅的可以参考本表格(冲这个可以要一个小小的关注吗?_(:з)∠)_)
2.1 创建信号(Signal)
下面的代码创建了一个名为“Alfa”的信号,“signal”关键字创建了一系列信号,“name”定义了信号名称,“wave”定义了信号波形,其中的每一个字符都表示了一个时间段的信号类型。
{ signal: [{ name: "Alfa", wave: "01.zx=ud.23.456789" }] }
具体的信号类型见下表:
2.2 添加时钟(Adding Clock)
时钟信号是一种比较特殊的信号,其只有高低电平两种状态。提供了可选的标志来控制是否展示出上升/下降沿。同时,可以与其他信号同时使用,用来实现类似门控时钟的绘制。
注意时钟的h和l与信号的1和0是不同的(变化沿的角度不同)。
下面代码实现了可供参考的时钟样式。
-
{ 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' },
-
]}
具体时钟类型见下表:
2.3 将时钟与信号结合(Putting all together)
我们在绘制时序图时,通常需要将时钟与信号放在一起,为了方便查看这两者之间的关系。不仅仅可以直接将时钟与信号结合,同时可以将你想添加的文字或数据名称,利用关键字“data”以标签的形式放入部分符号中,以表示总线的值。值是按先后顺序添加到“23456789=”这些符号中的。
下面的代码给出了使用的例子。
-
{ signal: [
-
{ name:
"clk", wave:
"P......" },
-
{ name:
"bus", wave:
"x.==.=x", data: [
"head",
"body",
"tail",
"data"] },
-
{ name:
"wire", wave:
"0.1..0." }
-
]}
2.4 添加间隙(Spacers and Gaps)
在时序图中,有时需要对时钟和信号进行省略,这就需要添加间隙省略掉不需要的部分。
-
{ 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." }
-
]}
2.5 为信号分组(The groups)
通过分组,可以更好地展示信号之间的层级关系,便于查阅和对比。使用"[ ]",可以实现对信号的分组,分组的名称可以选择性添加。
-
{ 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'},
-
],
-
]
-
]}
2.6 周期与相位(Period and Phase)
周期和相位是时序图中重要的属性,可以通过关键字“period”与“phase”来进行编辑修改。
注意period仅支持整数;phase支持整数与小数,且相位的单位1是指一个时段。
-
{ 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" }
-
]}
2.7 其他属性配置(The config{} property)
属性配置可以修改图像很多地方,增加绘图的灵活性,利用关键字“config”来对属性进行控制。
2.7.1 水平比例(hscale)
水平比例修改的是整幅图的水平宽度,直观理解为单位时段的绘图长度。
-
{ signal: [
-
{ name:
"clk", wave:
"p...." },
-
{ name:
"Data", wave:
"x345x", data: [
"head",
"body",
"tail"] },
-
{ name:
"Request", wave:
"01..0" }
-
],
-
config: { hscale:
1 }
-
}
当修改config: { hscale: 2 }时:
2.7.2 主题样式(skin)
通过“skin”关键字,可以修改图的整体主题样式。在离线版v2.9.1版本中提供了四种可选的参数“default”、“dark”、“lowkey”、“narrow”;在线版目前提供了两种可选参数“default”、“narrow”。
-
{ signal: [
-
{ name:
"clk", wave:
"p...." },
-
{ name:
"Data", wave:
"x345x", data: [
"head",
"body",
"tail"] },
-
{ name:
"Request", wave:
"01..0" }
-
],
-
config: { hscale:
2 ,
-
skin:
"lowkey"
-
}
-
}
2.7.3 头尾标注(head/foot)
关键字“head”与“foot”,可以通过头尾标注来对整幅图进行标注,包括text(标题文本)、tick(与垂直标记对其的标签)、tock(垂直标记之间的标签)、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
-
},
-
}
- text
text具有SVG文本的所有属性,可以通过“tspan”关键字对其属性进行修改,可以使用预定义的字体样式(包括下面表格中的类型,可以组合出需要的字体与颜色)、也可以使用SVG tspan的其他属性构成自由样式。
SVG tspan其他属性配置可以参考:tspan - SVG | MDN (mozilla.org)
-
{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
-
}
-
}
预定义的样式见下表:
2.8 标注箭头与线条(Arrows)
有时需要对时序图进行连接与标注,WaveDrom提供了相对应的实现。利用“edge”关键字,可以实现包括“曲线”与“折线”,同时都提供了有向与无向的配置方式;“折线”中提供了一种平角式箭头样式,便于对时间段长度进行标注。
共有三种线的类型,可以在使用中体会:
符号 | 曲线类型 |
~ | S型曲线 |
-与~组合 | 弧线 |
-或| | 直线 |
提供一个小tips:可能会认为连线只能是蓝色的,但是其实可以通过错误的语法,来实现红色连接线的绘制(但是均为无向)。
2.8.1 曲线(Splines)
下面的代码展示了曲线连接的案例,可以看到首先利用“node”关键字定义了需要连接的点,之后使用“edge”关键字对这些点进行了连接,通过使用不同的连接符号,可以实现不同的连接效果。
下面的代码给出了一个简单的使用案例。
-
{ 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'
-
]
-
}
具体的曲线定义见下表:
2.8.2 折线(Sharp lines)
下面的代码展示了折线连接的案例,可以看到首先利用“node”关键字定义了需要连接的点,之后使用“edge”关键字对他们进行了连接,通过使用不同的连接符号,可以实现不同的连接效果。
下面的代码给出一个简单的使用案例。
-
{ 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'
-
]
-
}
具体的折线定义见下表:
2.9 利用代码绘图(Some code)
WaveDrom提供了使用代码进行绘图的方式。例如可以通过循环迭代的方式生成依次递增的总线信号(如下面代码),将你从重复的劳动中解放出来。
简单分析一下这里的代码,通过使用关键字“function”,构建了函数,并在结尾进行调用,从而绘制了下面的图。
但我猜测对于大多数人来说,可能用不到这个功能,包括我自己还是更喜欢所见即所得的方式,所以就不作为本文的重点啦(我也没看太懂_(:з)∠)_)。
-
(
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)
至此就是WaveDrom的绘图教程啦,下一步,就是要将生成的图进行导出了(不会有人还在使用截图吧?)
3 图像保存与导出
WaveDrom提供了图像数据的保存以及导出方式,无论是离线版还是在线版,只需要点击右下角的“≡”按钮,即可找到。
分别介绍一下这几个按钮的功能:
按钮 | 功能 |
Load... | 读取存储的图形数据文件 |
Save As... | 将当前的图形数据文件存储为json |
Export SVG... | 导出矢量图 |
Export PNG... | 导出PNG图 |
Rotate Layout... | 旋转代码区与绘图区 |
Proportions | 修改代码区与绘图区比例 |
Expand URL | 拓展网址(不太明白) |
WaveDrom Guide | 打开官方使用指导(看这篇博客就够啦) |
on GitHub | 打开GitHub项目官网 |
至此,你学会WaveDrom了吗?没学会再看一遍(手动沟头)。
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞+收藏+关注,分享给身边的朋友哇~