simplify old posts' tags and categories

some blog contents are alse modified
This commit is contained in:
2023-04-13 00:32:29 +08:00
parent 95d3112612
commit c5f8b0a74c
19 changed files with 402 additions and 310 deletions
+3 -3
View File
@@ -66,8 +66,8 @@ creative_commons:
license: by-nc-sa
# Available values: big | small
size: small
sidebar: true
post: false
sidebar: false
post: true
# You can set a language value if you prefer a translated version of CC license, e.g. deed.zh
# CC licenses are available in 39 languages, you can find the specific and correct abbreviation you need on https://creativecommons.org
language: deed.zh
@@ -402,7 +402,7 @@ bookmark:
color: "#222"
# If auto, save the reading progress when closing the page or clicking the bookmark-icon.
# If manual, only save it by clicking the bookmark-icon.
save: auto
save: manual
# `Follow me on GitHub` banner in the top-right corner.
github_banner:
+16 -1
View File
@@ -110,6 +110,9 @@ deploy:
- type: git
repo: [email protected]:/home/josh/documents/josh-blog-deploy.git
branch: master
- type: git
repo: [email protected]:/home/josh/documents/josh-blog.git
branch: master
- type: git
repo: [email protected]:josh-gao/josh-blog/josh-blog.git
branch: master
@@ -192,4 +195,16 @@ neat_js:
- '**/*.min.js'
- '**/jquery.fancybox.pack.js'
- '**/index.js'
- '**/fireworks.js'
- '**/fireworks.js'
related_posts:
enabled: true
filter_threshold: 0.1
related_count: 5
weight:
title: 0.1
description: 0.05
keywords: 0.01
tags: 0.005
categories: 0.005
text: 1
+89
View File
@@ -21,6 +21,7 @@
"hexo-helper-live2d": "^3.1.1",
"hexo-neat": "^1.0.9",
"hexo-related-popular-posts": "^5.0.1",
"hexo-related-posts": "^1.5.1",
"hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-pandoc": "^0.3.1",
"hexo-renderer-stylus": "^2.1.0",
@@ -96,6 +97,15 @@
"node": ">=0.4.0"
}
},
"node_modules/afinn-165": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/afinn-165/-/afinn-165-1.0.4.tgz",
"integrity": "sha512-7+Wlx3BImrK0HiG6y3lU4xX7SpBPSSu8T9iguPMlaueRFxjbYwAQrp9lqZUuFikqKbd/en8lVREILvP2J80uJA==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
@@ -223,6 +233,17 @@
"node": ">= 8"
}
},
"node_modules/apparatus": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/apparatus/-/apparatus-0.0.10.tgz",
"integrity": "sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==",
"dependencies": {
"sylvester": ">= 0.0.8"
},
"engines": {
"node": ">=0.2.6"
}
},
"node_modules/aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/aproba/-/aproba-1.2.0.tgz",
@@ -4433,6 +4454,18 @@
"node": ">=0.10.0"
}
},
"node_modules/hexo-related-posts": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/hexo-related-posts/-/hexo-related-posts-1.5.1.tgz",
"integrity": "sha512-KeNGQXcfsDKGyP66wiUVlcqguMyBn0n9tsFE5CftxhD9jiOrCmsqCibY1Aq8w/9f92+uxl+NlNkFhkrLezRFVg==",
"dependencies": {
"natural": "^2.1.5"
},
"peerDependencies": {
"chalk": "^4.1.0",
"hexo": "^4.2.0 || ^5.2.0 || ^6.3.0"
}
},
"node_modules/hexo-renderer-ejs": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/hexo-renderer-ejs/-/hexo-renderer-ejs-2.0.0.tgz",
@@ -5909,6 +5942,17 @@
"resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"node_modules/json-stable-stringify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz",
"integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==",
"dependencies": {
"jsonify": "^0.0.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -5925,6 +5969,14 @@
"node": ">=6"
}
},
"node_modules/jsonify": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
"integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/jsonparse": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/jsonparse/-/jsonparse-1.3.1.tgz",
@@ -6782,6 +6834,22 @@
"node": ">=0.10.0"
}
},
"node_modules/natural": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/natural/-/natural-2.4.5.tgz",
"integrity": "sha512-fxQou4ubo6Rzf7XL0jjwtC2vHm6Sdicu7ztcE0k1ODZs+d1UzcKF1Hu2IwE2y7OgzU3Sa9o8obw7rnyNrjsd1A==",
"dependencies": {
"afinn-165": "^1.0.2",
"apparatus": "^0.0.10",
"json-stable-stringify": "^1.0.1",
"sylvester": "^0.0.12",
"underscore": "^1.9.1",
"wordnet-db": "^3.1.11"
},
"engines": {
"node": ">=0.4.10"
}
},
"node_modules/ncp": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/ncp/-/ncp-2.0.0.tgz",
@@ -9206,6 +9274,14 @@
"node": ">= 0.4"
}
},
"node_modules/sylvester": {
"version": "0.0.12",
"resolved": "https://registry.npmjs.org/sylvester/-/sylvester-0.0.12.tgz",
"integrity": "sha512-SzRP5LQ6Ts2G5NyAa/jg16s8e3R7rfdFjizy1zeoecYWw+nGL+YA1xZvW/+iJmidBGSdLkuvdwTYEyJEb+EiUw==",
"engines": {
"node": ">=0.2.6"
}
},
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -9519,6 +9595,11 @@
"node": ">=0.8.0"
}
},
"node_modules/underscore": {
"version": "1.13.6",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A=="
},
"node_modules/union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/union-value/-/union-value-1.0.1.tgz",
@@ -9954,6 +10035,14 @@
"node": ">=0.10.0"
}
},
"node_modules/wordnet-db": {
"version": "3.1.14",
"resolved": "https://registry.npmjs.org/wordnet-db/-/wordnet-db-3.1.14.tgz",
"integrity": "sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==",
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
+1
View File
@@ -25,6 +25,7 @@
"hexo-helper-live2d": "^3.1.1",
"hexo-neat": "^1.0.9",
"hexo-related-popular-posts": "^5.0.1",
"hexo-related-posts": "^1.5.1",
"hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-pandoc": "^0.3.1",
"hexo-renderer-stylus": "^2.1.0",
+25 -28
View File
@@ -3,19 +3,18 @@ title: MATLAB 函数 —— rcosdesign
tags:
- MATLAB
- 翻译
- 成型滤波器
- 成形滤波器
- 滤波器
categories:
- - MATLAB
- - 翻译
- 帮助文档
- [MATLAB, 函数用法]
mathjax: true
copyright: true
comments: true
abbrlink: 5c45edfe
date: 2020-11-25 22:32:42
---
`rcosdesign`:升余弦 FIR 脉冲成型滤波器设计
`rcosdesign`:升余弦 FIR 脉冲成形滤波器设计
# 语法
@@ -32,18 +31,18 @@ date: 2020-11-25 22:32:42
# 示例
## 设计根升余弦滤波器<span id="Examples-01"></span>
## 设计根升余弦滤波器<a name="Examples-01"></a>
将滚降系数设为 `0.25`,波器的符号数设为 `6`,每个符号 `4` 个采样点。验证 `sqrt` 是 `shape` 参数的默认值。
```m
``` matlab
h = rcosdesign(0.25,6,4);
mx = max(abs(h-rcosdesign(0.25,6,4,'sqrt')))
```
> <font face="Consolas">mx = 0</font><br>
```m
``` matlab
fvtool(h,'Analysis','impulse')
```
@@ -51,13 +50,13 @@ fvtool(h,'Analysis','impulse')
<img src="https://josh-blog-1257563604.cos.ap-beijing.myqcloud.com/img/2020-11-25-matlab-rcosdesign/2020-11-25-matlab-rcosdesign-010-DesignASquareRootRaisedCosineFilterExample-01.png?imageMogr2/thumbnail/!100p|watermark/2/text/QEpvc2ggR2Fv/fontsize/15/dissolve/60/gravity/southeast/dx/5/dy/5"/>
</div>
## 升余弦和根升余弦滤波器的脉冲响应<span id="Examples-02"></span>
## 升余弦和根升余弦滤波器的脉冲响应<a name="Examples-02"></a>
将升余弦滤波器与根升余弦滤波器进行比较。一个理想的(无限长)升余弦脉冲成型滤波器等效于两个级联的理想的根升余弦滤波器。因此,FIR 升余弦滤波器的脉冲响应应类似于与其自身卷积的根升余弦滤波器的脉冲响应。
将升余弦滤波器与根升余弦滤波器进行比较。一个理想的(无限长)升余弦脉冲成形滤波器等效于两个级联的理想的根升余弦滤波器。因此,FIR 升余弦滤波器的脉冲响应应类似于与其自身卷积的根升余弦滤波器的脉冲响应。
设计一个衰减为 `0.25` 的升余弦滤波器。指定滤波器有 `4` 个符号,每个符号 `3` 个采样点。
```m
``` matlab
rf = 0.25;
span = 4;
sps = 3;
@@ -72,7 +71,7 @@ fvtool(h1,'impulse')
**升余弦滤波器在 `sps` 的整数倍处具有零值点**。因此,它满足无码间串扰(ISI)的 Nyquist 准则。但是,根升余弦滤波器没有这样的特性:
```m
``` matlab
h2 = rcosdesign(rf,span,sps,'sqrt');
fvtool(h2,'impulse')
```
@@ -83,7 +82,7 @@ fvtool(h2,'impulse')
将根升余弦滤波器与自身进行卷积。在最大值处截断脉冲响应,使其长度与 `h1` 相同。使用最大值将响应归一化。然后,将卷积后的根升余弦滤波器与升余弦滤波器进行比较。
```m
``` matlab
h3 = conv(h2,h2);
p2 = ceil(length(h3)/2);
m2 = ceil(p2-length(h1)/2);
@@ -102,13 +101,13 @@ legend('h1','h2 * h2')
卷积响应的长度是有限的,因此根升余弦滤波器与自身进行卷积得到的结果会与升余弦滤波器不一致。增加 `span` 可以在响应之间获得更紧密的一致性,并更好地符合 Nyquist 准则。
## 将信号通过升余弦滤波器<span id="Examples-03"></span>
## 将信号通过升余弦滤波器<a name="Examples-03"></a>
本例说明如何将信号通过根升余弦滤波器。
指定滤波器参数。
```m
``` matlab
rolloff = 0.25; % 滚降因子
span = 6; % 滤波器宽度(符号数)
sps = 4; % 每个符号的样本数
@@ -116,31 +115,31 @@ sps = 4; % 每个符号的样本数
生成根升余弦滤波器的系数。
```m
``` matlab
b = rcosdesign(rolloff, span, sps);
```
生成双极性数据向量。
```m
``` matlab
d = 2*randi([0 1], 100, 1) - 1;
```
上采样并对数据进行滤波以实现脉冲成型。
上采样并对数据进行滤波以实现脉冲成形。
```m
``` matlab
x = upfirdn(d, b, sps);
```
添加噪声。
```m
``` matlab
r = x + randn(size(x))*0.01;
```
对接收到的信号进行滤波和下采样以进行匹配滤波。
```m
``` matlab
y = upfirdn(r, b, 1, sps);
```
@@ -196,6 +195,10 @@ y = upfirdn(r, b, 1, sps);
>>
>> 所有输入必须为常数。 如果表达式或变量的值不变,则也允许使用。
# 版本历史
在 R2013b 中推出
# 另请参阅
[`gaussdesign`](https://ww2.mathworks.cn/help/signal/ref/gaussdesign.html)
@@ -204,10 +207,4 @@ y = upfirdn(r, b, 1, sps);
[用 RRC 滤波器进行插值和抽取](https://ww2.mathworks.cn/help/comm/ug/interpolate-and-decimate-using-rrc-filter.html)(Communications Toolbox)
----
在 R2013b 中推出
----
原文参考:[https://ww2.mathworks.cn/help/signal/ref/rcosdesign.html](https://ww2.mathworks.cn/help/signal/ref/rcosdesign.html)
> 原文参考:[https://ww2.mathworks.cn/help/signal/ref/rcosdesign.html](https://ww2.mathworks.cn/help/signal/ref/rcosdesign.html)
+13 -16
View File
@@ -3,19 +3,18 @@ title: MATLAB 函数 —— gaussdesign
tags:
- MATLAB
- 翻译
- 成型滤波器
- 成形滤波器
- 滤波器
categories:
- - MATLAB
- - 翻译
- 帮助文档
- [MATLAB, 函数用法]
mathjax: true
copyright: true
comments: true
abbrlink: a2967b00
date: 2020-11-26 15:56:26
---
`gaussdesign`:高斯 FIR 脉冲成型滤波器设计
`gaussdesign`:高斯 FIR 脉冲成形滤波器设计
# 语法
@@ -25,15 +24,15 @@ date: 2020-11-26 15:56:26
# 说明
`h = gaussdesign(bt,span,sps)` 设计一个低通 FIR 高斯脉冲成型滤波器,并返回滤波器系数向量 `h`。滤波器有 `span` 个符号,每个符号包含 `sps` 个样本。滤波器的阶次,也即 `sps * span` 必须是偶数。[举例](#Examples-01)
`h = gaussdesign(bt,span,sps)` 设计一个低通 FIR 高斯脉冲成形滤波器,并返回滤波器系数向量 `h`。滤波器有 `span` 个符号,每个符号包含 `sps` 个样本。滤波器的阶次,也即 `sps * span` 必须是偶数。[举例](#Examples-01)
# 示例
## GSM GMSK 数字蜂窝通信系统的高斯滤波器<span id="Examples-01"></span>
## GSM GMSK 数字蜂窝通信系统的高斯滤波器<a name="Examples-01"></a>
指定用于传输比特位的调制是高斯最小频移键控(GMSK)脉冲。此脉冲的 3-dB 带宽等于比特率的 `0.3` 倍,滤波器的符号数为 `4`,每个符号 `8` 个采样点。
```m
``` matlab
bt = 0.3;
span = 4;
sps = 8;
@@ -69,7 +68,7 @@ fvtool(h,'impulse')
## `h` - FIR 滤波器系数
高斯脉冲成型滤波器的 FIR 系数,以**行向量**的形式返回。系数已被归一化,因此标称通带增益始终为 1。
高斯脉冲成形滤波器的 FIR 系数,以**行向量**的形式返回。系数已被归一化,因此标称通带增益始终为 1。
**数据类型**:`double` | `single`
@@ -79,14 +78,12 @@ fvtool(h,'impulse')
[2] Rappaport, Theodore S. *Wireless Communications: Principles and Practice.* 2nd Ed. Upper Saddle River, NJ: Prentice Hall, 2002.
# 版本历史
在 R2013b 中推出
# 另请参阅
[`rcosdesign`](https://ww2.mathworks.cn/help/signal/ref/rcosdesign.html)
---
在 R2013b 中推出
---
原文参考:[https://ww2.mathworks.cn/help/signal/ref/gaussdesign.html](https://ww2.mathworks.cn/help/signal/ref/gaussdesign.html)
原文参考:[https://ww2.mathworks.cn/help/signal/ref/gaussdesign.html](https://ww2.mathworks.cn/help/signal/ref/gaussdesign.html)
+15 -15
View File
@@ -5,14 +5,14 @@ tags:
- 翻译
- 上采样
categories:
- - MATLAB
- - 翻译
- 帮助文档
- [MATLAB, 函数用法]
mathjax: true
copyright: true
comments: true
abbrlink: 3a606c9c
date: 2020-11-26 22:23:39
---
`upsample`:将采样率提高整数倍
# 语法
@@ -30,16 +30,16 @@ date: 2020-11-26 22:23:39
# 示例
## 提高采样率<span id="Examples-01"></span>
## 提高采样率<a name="Examples-01"></a>
将序列的采样率提高 `3` 倍。
```m
``` matlab 输入
x = [1 2 3 4];
y = upsample(x,3)
```
```no
``` plain 输出
y = 1×12
1 0 0 2 0 0 3 0 0 4 0 0
@@ -47,12 +47,12 @@ y = 1×12
将序列的采样率增加 `3` 倍,并将相位偏移增加 `2`。
```m
``` matlab 输入
x = [1 2 3 4];
y = upsample(x,3,2)
```
```no
``` plain 输出
y = 1×12
0 0 1 0 0 2 0 0 3 0 0 4 0
@@ -60,14 +60,14 @@ y = 1×12
将矩阵的采样率提高3倍。
```m
``` matlab 输入
x = [1 2;
3 4;
5 6];
y = upsample(x,3)
```
```no
``` plain 输出
y = 9×2
1 2
@@ -115,12 +115,12 @@ y = 9×2
> 使用 MATLAB® Coder™ 生成 C 代码和 C++ 代码。
# 版本历史
在 R2006a 之前推出
# 另请参阅
[`decimate`](https://ww2.mathworks.cn/help/signal/ref/decimate.html) | [`downsample`](https://ww2.mathworks.cn/help/signal/ref/downsample.html) | [`interp`](https://ww2.mathworks.cn/help/signal/ref/interp.html) | [`interp1`](https://ww2.mathworks.cn/help/matlab/ref/interp1.html) | [`resample`](https://ww2.mathworks.cn/help/signal/ref/resample.html) | [`spline`](https://ww2.mathworks.cn/help/matlab/ref/spline.html) | [`upfirdn`](https://ww2.mathworks.cn/help/signal/ref/upfirdn.html)
--------------------------------------------------------------------------------
在 R2006a 之前推出
--------------------------------------------------------------------------------
原文参考:[https://ww2.mathworks.cn/help/signal/ref/upsample.html](https://ww2.mathworks.cn/help/signal/ref/upsample.html)
> 原文参考:[https://ww2.mathworks.cn/help/signal/ref/upsample.html](https://ww2.mathworks.cn/help/signal/ref/upsample.html)
@@ -5,8 +5,10 @@ tags:
- Hexo
- Next
categories:
- [Blog, Hexo, Next]
- [Blog, Hexo]
abbrlink: e96c9b26
copyright: true
comments: true
date: 2020-11-27 11:15:21
---
@@ -8,13 +8,11 @@ tags:
- 行为级
- RTL
- 寄存器传输级
categories:
- [Verilog, Verilog 简介]
categories:
- [Josh 的学习笔记, Verilog]
mathjax: true
comments: true
copyright: true
sticky: false
toc:
enable: true
number: false
+24 -26
View File
@@ -5,13 +5,11 @@ tags:
- 翻译
- 高斯白噪声
categories:
- - MATLAB
- - 翻译
- 帮助文档
- - 信号处理
- 噪声
- [MATLAB, 函数用法]
- [信号处理, 噪声]
mathjax: true
copyright: true
comments: true
abbrlink: 2f6db45b
date: 2020-11-27 01:15:12
---
@@ -49,14 +47,14 @@ date: 2020-11-27 01:15:12
创建一个锯齿波。
```m
``` matlab
t = (0:0.1:10)';
x = sawtooth(t);
```
添加高斯白噪声并绘制结果。
```m
``` matlab
y = awgn(x,10,'measured');
plot(t,[x y])
legend('Original Signal','Signal with AWGN')
@@ -72,32 +70,32 @@ legend('Original Signal','Signal with AWGN')
根据电话线调制解调器的 V.29 标准创建一个 16-QAM 星座。
```m
``` matlab
c = [-5 -5i 5 5i -3 -3-3i -3i 3-3i 3 3+3i 3i -3+3i -1 -1i 1 1i];
M = length(c);
```
生成随机符号。
```m
``` matlab
data = randi([0 M-1],2000,1);
```
使用 `genqammod` 函数调制数据。由于星座图不是矩形,因此必须进行常规 QAM 调制。
```m
``` matlab
modData = genqammod(data,c);
```
使信号通过具有 20 dB 信噪比(SNR)的 AWGN 信道。
```m
``` matlab
rxSig = awgn(modData,20,'measured');
```
显示接收信号的星座图和参考星座图。
```m
``` matlab
h = scatterplot(rxSig);
hold on
scatterplot(c,[],[],'r*',h)
@@ -111,25 +109,25 @@ hold off
使用 `genqamdemod` 函数解调接收到的信号。计算误符号数和误符号率。
```m
``` matlab 输入
demodData = genqamdemod(rxSig,c);
[numErrors,ser] = symerr(data,demodData)
```
```no
``` plain 输出
numErrors = 1
ser = 5.0000e-04
```
使用具有 10 dB SNR 的 AWGN 信道重复传输和解调过程。计算降低 SNR 后的误符号率。不出所料,当 SNR 降低时,性能会下降。
```m
``` matlab 输入
rxSig = awgn(modData,10,'measured');
demodData = genqamdemod(rxSig,c);
[numErrors,ser] = symerr(data,demodData)
```
```no
``` plain 输出
numErrors = 462
ser = 0.2310
```
@@ -140,7 +138,7 @@ ser = 0.2310
将 X 的功率指定为 0 dBW,添加噪声以产生 10 dB 的 SNR,并利用本地随机流。
```m
``` matlab 输入
S = RandStream('mt19937ar','Seed',5489);
sigin = sqrt(2)*sin(0:pi/8:6*pi);
sigout1 = awgn(sigin,10,0,S);
@@ -148,25 +146,25 @@ sigout1 = awgn(sigin,10,0,S);
将 AWGN 添加到 `sigin`。 使用 [`isequal`](https://ww2.mathworks.cn/help/matlab/ref/isequal.html) 比较 `sigout1` 和 `sigout2`。 当不重置随机流时,输出不相等。
```m
``` matlab 输入
sigout2 = awgn(sigin,10,0,S);
isequal(sigout1,sigout2)
```
```no
``` plain 输出
ans = logical
0
```
重置随机流对象,将对象置为初始状态,然后再将 AWGN 添加到 `sigout1`。将 AWGN 添加到 `sigin` 并将 `sigout1` 与 `sigout3` 比较。 重置随机流后,输出相等。
```m
``` matlab 输入
reset(S);
sigout3 = awgn(sigin,10,0,S);
isequal(sigout1,sigout3)
```
```no
``` plain 输出
ans = logical
1
```
@@ -260,6 +258,10 @@ ans = logical
>>
>> 支持代码生成,但包括 [`RandStream`](https://ww2.mathworks.cn/help/matlab/ref/randstream.html) 对象的语法除外。
# 版本历史
在 R2006a 之前推出
# 另请参阅
## 函数
@@ -274,8 +276,4 @@ ans = logical
[AWGN Channel Noise Level](https://ww2.mathworks.cn/help/comm/ug/awgn-channel.html#a1071501088)
--------------------------------------------------------------------------------
在 R2006a 之前推出
--------------------------------------------------------------------------------
原文参考:[https://ww2.mathworks.cn/help/comm/ref/awgn.html](https://ww2.mathworks.cn/help/comm/ref/awgn.html)
原文参考:[https://ww2.mathworks.cn/help/comm/ref/awgn.html](https://ww2.mathworks.cn/help/comm/ref/awgn.html)
@@ -8,7 +8,6 @@ tags:
- 自底向上
- Verilog 语法
categories:
- [Verilog, Verilog 语法]
- [Josh 的学习笔记, Verilog]
mathjax: true
comments: true
@@ -63,7 +62,7 @@ EDA 行业的先行者们发明了 Verilog 硬件描述语言,其最根本的
**这些电路单元都是同时并行工作的,相互之间并没有先后顺序关系,这一点与软件设计程序很不一样。**
下面具体分析 [JoshVerilog 模块](#JoshVerilog模块)的电路功能。源代码如下。
下面具体分析 [JoshVerilog 模块](#JoshVerilog模块) 的电路功能。源代码如下。
<a name="JoshVerilog代码"></a>
@@ -260,7 +259,7 @@ reg eq3;
module 模块名称( 端口列表 );
// 声明:
reg, parameter,
input, output,
input, output,
function, task, ...
// 语句:
initial 语句
@@ -288,7 +287,7 @@ input [1:0] A_in;
模块内部使用的 `reg`(寄存器类型的一种)、`wire`(线网类型的一种)、参数、函数以及任务等,都将在 `module` 中声明。
一般来说,`module` 的
一般来说,`module` 的
- `input` 默认定义为 `wire` 类型;
- `output` 信号可以是 `wire`,也可以是 `reg` 类型(如果在 `always` 或 `initial` 语句块中被赋值);
@@ -499,9 +498,9 @@ Message = "HeIIo World";
### 7.2.1 `reg` 类型
1. 寄存器类型数
`reg` 类型可以定位为一个寄存器,可以定义一位或者多位,例如:
```verilog
reg AB; // 定义一个名为 AB 的 1 位寄存器
reg [3:0] ABC; // 定义一个名为 ABC 的 4 位寄存器
@@ -516,9 +515,9 @@ Message = "HeIIo World";
```
这样,整个 `ABC` 变量的值为 `4'b1010`。
2. 寄存器类型数组
`reg` 类型可以作为二维数组,也就是存储器,例如:
```verilog
@@ -532,7 +531,7 @@ Message = "HeIIo World";
```
同时,在 Verilog 中,不存可以对整个存储器赋值的语句,必须对每个单元独立赋值。除非使用 `$readmemb` 或 `$readmemh` 系统任务从文件中读入整个或者部分存储器的数据。
[comment]: <> (在第7章将讨论如何从文件中读入数据给存储器赋值。)
### 7.2.2. `integer` 类型
+27 -28
View File
@@ -8,7 +8,6 @@ tags:
- 设计层次
- Verilog 语法
categories:
- [Verilog, Verilog 设计]
- [Josh 的学习笔记, Verilog]
mathjax: true
comments: true
@@ -64,23 +63,23 @@ assign #1 A_xor_wire = eq0 ^ eq1;
### 2.2.1. 连续赋值语句的特点
1. **连续驱动**
在 [Part 2 的 7.2 驱动和赋值](https://josh-gao.top/posts/fd2ca242.html#%E5%AF%84%E5%AD%98%E5%99%A8%E7%B1%BB%E5%9E%8B)部分,已经解释了驱动和赋值之间的微妙区别。
连续赋值语句是连续驱动的。也就是说,任何时刻输入的任何变化都将导致该语句的重新计算。
2. **只有线网类型能在 `assign` 中赋值**
由于仿真器中不会存储连续赋值语句中被赋值的变量值,因此该变量是线网类型(Net),不能是寄存器类型。需要记住,只有线网类型的变量才可以在 `assign` 语句中被赋值。
另外,线网类型的变量可以被多重驱动,也就是说,可以在多个连续赋值语句中驱动同一个线网。在[2.4 驱动源线网](#drive)中将进一步介绍。但是,寄存器变量就不同了,它不能被不同的行为进程(例如 `always` 语句块)驱动。
3. **使用 `assign` 对组合逻辑建模**
通常建议使用 `assign` 对组合逻辑建模。因为 `assign` 语句的连续驱动特点与组合逻辑的行为非常相似。而且,在 `assign` 语句中加延时可以非常精确的模拟组合逻辑的惯性延时。
4. **并行性**
`assign` 语句和行为语句块(`always` 和 `initial`)、其他连续赋值语句、门级模型之间是并行的。一个连续赋值语句是一个独立的进程,进程之间是并发,同时也是交织的。
### 2.2.2. 实例
@@ -105,7 +104,7 @@ output C_out;
assign sum = X ^ Y;
assign C_out = X & Y;
endmodule
endmodule
```
```verilog FullAdd.v
@@ -131,15 +130,15 @@ HalfAdd u_HalfAdd_A(
.s (HalfAdd_A_sum),
.C_out (HalfAdd_A_Cout)
);
HalfAdd u_HalfAdd_B(
.X (C_in),
.Y (HalfAdd_A_sum),
.s (sum),
.C_out (HalfAdd_B_Cout)
);
endmodule
endmodule
```
在 `HalfAdd` 模块中,两个 `assign` 语句之间是**完全并行独立执行**的,它们的顺序与逻辑功能无关。同样,`FullAdd` 模块中,两个 `HalfAdd` 的实例和或门的 `assign` 语句之间的关系也是独立的。
@@ -329,7 +328,7 @@ always // 每 5ns 将 clk 翻转一次
下面的代码描述了语句组和高级编程语句的互相嵌套:
```verilog
always @(posedge clk or negedge rst_n)
always @(posedge clk or negedge rst_n)
begin // 语句组
if (~rst_n) // 高级编程语句
begin // 语句组
@@ -605,7 +604,7 @@ end
always @(negedge clk)
Q = D;
endmodule
```
@@ -873,18 +872,18 @@ endcase
循环语句后面可以跟语句或语句组(`begin ... end` 或 `fork ... join`)。
1. `forever` 循环:永远执行
```verilog
initial begin
clk = 0;
forever #25 clk = ~clk;
end
```
以上语句产生了一个周期为 50 个时间单位的时钟。
2. `repeat` 循环:执行固定的次数
```verilog
if (rotate == 1)
repeat (8)
@@ -893,11 +892,11 @@ endcase
data = {data<<1, temp};
end
```
以上语句中,当为 1 时,重复对 `data` 数据做8次循环左移。
3. `while` 循环:当表达式为真时执行
```verilog
initial begin
count = 0;
@@ -907,11 +906,11 @@ endcase
end
end
```
在 `while` 语句中,只要后面的条件满足,就持续执行该语句,直到条件不满足,跳出循环。这里,将 `count` 从 0 递增到 101,逐步打印出来。
4. `for` 循环:从初始值开始,如果表达式为真就执行
```verilog
integer i; // 为 for 循环声明索引
always @(inp or cnt) begin
@@ -924,7 +923,7 @@ endcase
end
end
```
`for` 语句开始执行直到 `i` 大于 7,跳出循环。如上代码实现了一个位的左移器。
简单介绍了 Verilog 中的高级编程语句,只要对 C 语言有一定基础,就能迅速掌握其中的用法。
@@ -948,7 +947,7 @@ output C_out;
xor u_xor(sum, X, Y); // 门级原语实例
and u_and(C_out, X, Y); // 门级原语实例
endmodule
endmodule
```
```verilog FullAdd.v
@@ -973,15 +972,15 @@ HalfAdd u_HalfAdd_A( // 半加器实例 A
.sum (HalfAdd_A_sum),
.C_out (HalfAdd_A_Cout)
);
HalfAdd u_HalfAdd_B( // 半加器实例 B
.X (C_in),
.Y (HalfAdd_A_sum),
.sum (sum),
.C_out (HalfAdd_B_Cout)
);
endmodule
endmodule
```
上例已将[原半加器代码](#半加器代码)中的语句改为门原语的实例化。在全加器的模块中,有两个半加器模块的实例和一个 `or` 门原语的实例。
@@ -1157,7 +1156,7 @@ defparam
altsyncram_component.widthad_a = 5, // 5 位地址
altsyncram_component.width_a = 8, // 8 位宽的数据
altsyncram_component.width_byteena_a = 1;
endmodule
```
@@ -1362,7 +1361,7 @@ output C_out;
xor u_xor(sum, X, Y); // 门级原语实例
and u_and(C_out, X, Y); // 门级原语实例
endmodule
endmodule
```
其中直接调用了 `xor` 和 `and` 的两个 Verilog 门原语。
+155 -156
View File
@@ -21,7 +21,6 @@ tags:
- 异步复位
- 条件语句
categories:
- [Verilog]
- [Josh 的学习笔记, Verilog]
abbrlink: ecb88422
date: 2020-12-02 01:05:32
@@ -54,15 +53,15 @@ RTL 级语言的最重要特性就是:{% label primary @RTL 级描述是可综
典型的 RTL 设计包含以下3个部分:
1. 时钟域描述
描述设计所使用的所有时钟,时钟之间的主从与派生关系,时钟域之间的转换。
2. 时序逻辑描述(寄存器描述)
根据时钟沿的变换,描述寄存器之间的数据传输方式。
3. 组合逻辑描述
描述电平敏感信号的逻辑组合方式与逻辑功能。
RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了设计的性能,如何调整时序逻辑、组合逻辑的连接关系和拓扑结构以达到最佳的性能就是后面讨论的编码风格(Coding Style)的核心。
@@ -70,11 +69,11 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
工程师们设计 RTL 级代码的顺序各种各样,推荐使用如下的设计步骤:
1. **功能定义与模块划分**
根据系统功能的定义和模块划分准则(详见Part 5 第 4 节)划分各个功能模块。
2. **定义所有模炔的接口**
首先清晰定义每个模块的接口,完成每个模块的信号列表。这种思路也和 Modular Design(模块化设计方法)一致,利于模块重用、调试、修改。
3. **设计的时钟域**
@@ -88,7 +87,7 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
关键路径是指设计中时序要求最难以满足的路径。设计的时序要求主要体现在频率、建立时间、保持时间等时序指标上。在设计初期,设计者可以根据系统的频率要求,粗略地分析出设计的时序难点(如最高频率的路径,计数器的最低位,包含复杂组合逻辑的时序路径等),通过一些时序优化手段(如 Pipeline、Retiming、逻辑复制等,这些时序优化手段在 Part 5 第 7 节有详细介绍)**从代码上缓解设计的时序压力**,这种方法比单依靠综合与布局布线工具的自动优化有效得多。
5. **顶层设计**
常用的设计方法有两种,一种是自顶而下的设计方法,即先描述设计的顶层,然后描述设计的每个子模块;另一种是由底向上的设计方法,即首先描述设计的子模块,最后定义设计的顶层。RTL 设计推荐使用自顶而下的设计方法,因为这种设计方法与模块规划的顺序一致,而且更利于进行 Modular Design(模块化设计方法),并行开展设计工作,提高模块重用率。
6. **FSM 设计**
@@ -100,7 +99,7 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
首先根据时钟域规划好寄存器组,然后描述各个寄存器组之间的数据传输方式。
8. **组合逻辑设计**
一般来说,**大段的组合逻辑最好与时序逻辑分开描述**,这样更利于时序约束和时序分析,使综合器和布局布线器达到更好的优化效果。
# 3. 常用 RTL 级建模
@@ -110,66 +109,66 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
有很多文章论述阻塞赋值和非阻塞赋值的概念,[《Part 3 —— 描述方式和设计层次》的 3.2 小节](https://josh-gao.top/posts/fd117896.html#3-2-%E8%BF%87%E7%A8%8B%E8%B5%8B%E5%80%BC%E8%AF%AD%E5%8F%A5)详细讨论了因不当使用阻塞赋值和非阻塞赋值引起的仿真与设计意图不一致。为了避免不当使用阻塞賦值和非阻塞赋值而造成的种种歧义和错误,这里推荐:
1. **对于时序逻辑,即 `always` 模块的敏感表为{% label primary @沿敏感信号 %}(多为时钟或复位的正沿或负沿),统一使用非阻塞賦值 `<=`**。例如:
```verilog // cnt1.v
/******************************
时序逻辑中使用非阻塞赋值。
******************************/
module cnt1 (clock, cnt_out);
input clock;
output [3:0] cnt_out;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [3:0] cnt_out;
always @(posedge clock)
cnt_out <= cnt_out + 1;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
2. **对于 `always` 模块的敏感表为{% label primary @电平敏感 %}信号的组合逻辑,统一使用阻塞賦值**。例如:
<span id="cnt2.v"></span>
```verilog cnt2.v
/******************************
always 模块的敏感表为电平敏感信号的组合逻辑, 使用阻塞赋值。请注意, 此例
"cnt_out_plus"虽然被指定为 reg 型, 但是实现时是纯组合逻辑。
******************************/
module cnt2 (cnt_out, cnt_out_plus);
input [3:0] cnt_out;
output [3:0] cnt_out_plus;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [3:0] cnt_out_plus;
always @(cnt_out)
cnt_out_plus = cnt_out + 1;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
3. **对于 `assign` 关键字描述的{% label primary @组合逻辑 %},称为连续赋值语句,统一使用 `=`,变量被定义为 `wire` 型信号**。例如:
```verilog cnt3.v
/******************************
assign 描述的组合逻辑。"cnt_out_plus"被定义为 wire 型信号。
******************************/
module cnt3 (cnt_out, cnt_out_plus);
input [3:0] cnt_out;
output [3:0] cnt_out_plus;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
wire [3:0] cnt_out_plus;
assign cnt_out_plus = cnt_out + 1;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -197,35 +196,35 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
******************************/
module cnt4 (clock, cnt_out);
input clock;
output [3:0] cnt_out;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [3:0] cnt_out;
always @(negedge clock)
cnt_out <= cnt_out + 1;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
3. **异步复位/置位**:绝大多数目标器件的寄存器模型都包含异步复位/置位端。异步复位/置位是指无论时钟沿是否有效,当复位/置位信号有效沿到达时,复位/置位立即发挥功能。指定异步复位/置位时,**只需在 `always` 的敏感表中加入复位/置位信号的有效沿即可**。下例描述的异步复位电路是最常用的寄存器复位形式之一。
```verilog
/******************************
最常用的异步复位电路, 设异步复位信号"reset_"是低有效信号(也即下降沿开始复位)。用户可
以在 begin/end 结构之间填入复杂的用户逻辑。
******************************/
// reg_counter.v
module reg_counter (clock, reset_, cnt_reg_s, cnt_reg_a);
input clock;
input reset_;
output [3:0] cnt_reg_s;
output [3:0] cnt_reg_a;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [3:0] cnt_reg_s; //asynchronous reset
always @(posedge clock or negedge reset_)
@@ -236,7 +235,7 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
cnt_reg_s [3] <= ~cnt_reg_s [3];
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
reg [3:0] cnt_reg_a; //synchronous reset
always @(posedge clock)
if (!reset_)
@@ -245,25 +244,25 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
cnt_reg_a [2:0] <= cnt_reg_a [2:0] + 1;
cnt_reg_a [3] <= ~cnt_reg_a [3];
end
endmodule
```
4. **同步复位/置位**:任何寄存器都可实现同步复位/置位功能。指定同步复位/置位时,**`always` 的敏感表中仅有时钟沿信号**,当同步复位/置位信号变化时,同步复位/置位并不立即发生,仅仅当时钟沿采到同步复位/置位的有效电平时,才会在时钟沿到达时刻进行复位/置位操作。
```verilog reg_counter.v
/******************************
常用的同步复位电路, 设异步复位信号"reset_"是低电平有效信号。请比较上例, 对比 always
常用的同步复位电路, 设异步复位信号"reset_"是低电平有效信号。请比较上例, 对比 always
的敏感表。
******************************/
module reg_counter (clock, reset_, cnt_reg_s, cnt_reg_a);
input clock;
input reset_;
output [3:0] cnt_reg_s;
output [3:0] cnt_reg_a;
reg [3:0] cnt_reg_s; //asynchronous reset
always @ (posedge clock or negedge reset_)
if (!reset_)
@@ -272,7 +271,7 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
cnt_reg_s [2:0] <= cnt_reg_s [2:0] + 1;
cnt_reg_s [3] <= ~cnt_reg_s [3];
end
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [3:0] cnt_reg_a; //synchronous reset
always @ (posedge clock)
@@ -283,24 +282,24 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
cnt_reg_a [3] <= ~cnt_reg_a [3];
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
> 关于同步复位和异步复位的优缺点,在 [3.9 小节](#0309) 有详细介绍。
5. **同时使用时钟上升和下降沿的问题**:有时因为数据采样或调整数据相位等需求,设计者会在一个 `always` 的敏感表中同时使用时钟的 `posedge` 和 `negedge`,或者在两个 `always` 的敏感表中分别使用时钟的 `posedge` 和 `negedge` 对某些寄存器电路操作。在这两种描述下,当时钟上沿或下沿到达时,该寄存器电路都会做相应的操作。**这个双沿电路往往可以等同于使用了原时钟的倍频时钟的单沿操作电路**。对于实现在 PLD 的设计而言,同时使用时钟的上、下沿往往是不推荐的,因为 PLD 内嵌的 PLL/DLL 和一些时钟电路往往只能对时钟的一个沿保证非常好的指标,而另个沿的抖动、偏斜、斜率等指标不见得非常优化,有时同时使用时钟的正负沿会因时钟的抖动、偏斜、占空比、斜率等问题造成一定的性能恶化。因此推荐的做法是:将原时钟通过 PLL/DLL 倍频,然后使用倍频时钟的单沿(如上升沿)进行操作。但是电路设计不可一概而论,如果必须使用时钟的双沿对同一个寄存器操作时,请设计者明确此时相当于使用了倍频时钟。
```verilog clock_edge.v
/******************************
某电路使用 50MHz 时钟双沿操作相当于使用同相位 100MHz 倍频时钟操作。
******************************/
module clock_edge (clk_50M, clk_100M, rst_, cnt1, cnt2);
input clk_50M, clk_100M, rst_;
output [3:0] cnt1, cnt2;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [3:0] cnt_temp1, cnt_temp2;
wire [3:0] cnt1;
@@ -309,45 +308,45 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
cnt_temp1 <= 4'b0000;
else
cnt_temp1 <= cnt_temp2 + 1;
always @(negedge clk_50M or negedge rst_ )
if (!rst_)
cnt_temp2 <= 4'b0000;
else
cnt_temp2 <= cnt_temp1 + 1;
assign cnt1 = (clk_50M)? cnt_temp2 : cnt_temp1;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
reg [3:0] cnt2;
always @(posedge clk_100M or negedge rst_ )
if (!rst_)
cnt2 <= 4'b0000;
else
cnt2 <= cnt2 + 1;
endmodule
```
这里相当于使用与 50MHz 时钟 `clk_50M` 同相位的 2 倍频时钟 `cIk_100M` 进行累加计算,等效描述如下:
```verilog
reg [3:0] cnt2;
always @(posedge clk_100M or negedge rst_ )
if (!rst_)
cnt2 <= 4'b0000;
else
cnt2 <= cnt2 + 1;
```
以上代码综合后,对应的电路结构如[图 4-1](#图4-1) 所示。
<a name="图4-1"></a>
<div align="center">
<img src="https://josh-blog-1257563604.cos.ap-beijing.myqcloud.com/img/2020-12-02-josh-verilog-part-4/2020-12-02-josh-verilog-part-4-010-RegisterCircuitModeling-01.png!900px" alt="某双沿加法电路与等价倍频时钟单沿加法电路结构示意图"/>
</div>
RTL 仿真波形如[图 4-2](#图4-2) 所示。
<a name="图4-2"></a>
@@ -369,20 +368,20 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
/******************************
某组合逻辑译码电路。
******************************/
module decode_cmb (addr, CS, cs1, cs2, cs3, cs4);
input [7:0] addr; // only the 2 MSB bits used
input CS; // Low effect
output cs1, cs2, cs3, cs4; // Low effect
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg cs1, cs2, cs3, cs4;
parameter chip1_decode = 2'b00,
chip2_decode = 2'b01,
chip3_decode = 2'b10,
chip4_decode = 2'b11;
always @(CS or addr)
if (CS)
{cs1, cs2, cs3, cs4} = 4'b1111;
@@ -392,10 +391,10 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
chip2_decode: {cs1, cs2, cs3, cs4} = 4'b1011;
chip3_decode: {cs1, cs2, cs3, cs4} = 4'b1101;
chip4_decode: {cs1, cs2, cs3, cs4} = 4'b1110;
endcase
endcase
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -407,16 +406,16 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
</div>
2. `assign` 等语句描述的组合逻辑电路
这种形式描述组合逻辑电路适用于描述那些相对简单的组合逻辑。信号一般被定义为 `wire` 型,常用的 `assign` 结构除了直接赋值逻辑表达式外,还可以使用 `?` 语句。
```verilog decode_cmb2.v
/******************************
使用 assign 结构描述该组合逻辑译码电路。
******************************/
module decode_cmb2 (addr, CS, cs1, cs2, cs3, cs4);
input [7:0] addr; // only the 2 MSB bits used
input CS; // Low effect
output cs1, cs2, cs3, cs4; // Low effect
@@ -427,13 +426,13 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
chip2_decode = 2'b01,
chip3_decode = 2'b10,
chip4_decode = 2'b11;
assign cs1 = (!CS && (addr[7:6] == chip1_decode))? 0 : 1 ;
assign cs2 = (!CS && (addr[7:6] == chip2_decode))? 0 : 1 ;
assign cs3 = (!CS && (addr[7:6] == chip3_decode))? 0 : 1 ;
assign cs4 = (!CS && (addr[7:6] == chip4_decode))? 0 : 1 ;
assign cs1 = (!CS && (addr[7:6] == chip1_decode))? 0 : 1 ;
assign cs2 = (!CS && (addr[7:6] == chip2_decode))? 0 : 1 ;
assign cs3 = (!CS && (addr[7:6] == chip3_decode))? 0 : 1 ;
assign cs4 = (!CS && (addr[7:6] == chip4_decode))? 0 : 1 ;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -457,7 +456,7 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
/******************************
将双向总线 data_bus 分为输入总线 data_in 和输出总线 data_in, 然后分别使用。
******************************/
module bibus (clk, rst, sel, data_bus, addr);
input clk, rst, sel;
input [7:0] addr;
@@ -465,11 +464,11 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
inout [7:0] data_bus;
wire [7:0] data_in, data_out;
assign data_in = data_bus;
assign data_bus = (sel) ? data_out : 8'bZ;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
decode decode_inst (
.clock (clk),
.reset (rst),
@@ -485,27 +484,27 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
```verilog
assign data_bus = (sel) ? data_out : 8'bZ;
```
2. 如果三态总线的使能关系比较复杂,不是单一信号,此时可以使用嵌套的问号表达式,或者使用语句描述(当然也可以用 `if ... else` 结构)。
```verilog complex_bibus.v
/******************************
双向总线 databus 的输出由 3 个使能信号 sel1、sel2、se13共同确定, 下述代码中中使用嵌
套的问号表达式描述了该三态总线的使能选择。
******************************/
module complex_bibus (clk, rst, sel1, sel2, sel3, data_bus, addr);
input clk, rst;
input sel1, sel2, sel3;
input [7:0] addr;
wire [7:0] data_in;
//wire [7:0] data_out; //use wire type
wire [7:0] decode_out;
wire [7:0] cnt_out;
assign data_in = data_bus;
decode decode_inst (
.clock (clk),
.reset (rst),
@@ -513,20 +512,20 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
.addr_bus (addr),
.data_bus_out (decode_out)
);
counter counter_inst (
.clock (clk),
.reset (rst),
.data_bus_in (data_in),
.cnt_out (cnt_out)
);
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
inout [7:0] data_bus;
assign data_bus = (sel1)? decode_out : ((sel2)? cnt_out : ((sel3)? 8'b11111111:
assign data_bus = (sel1)? decode_out : ((sel2)? cnt_out : ((sel3)? 8'b11111111:
8'bZZZZZZZZ));
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -543,9 +542,9 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
input clk, rst;
input sel1, sel2, sel3;
input [7:0] addr;
assign data_in = data_bus;
decode decode_inst (
.clock (clk),
.reset (rst),
@@ -553,34 +552,34 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
.addr_bus (addr),
.data_bus_out (decode_out)
);
counter counter_inst (
.clock (clk),
.reset (rst),
.data_bus_in (data_in),
.cnt_out (cnt_out)
);
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
inout [7:0] data_bus;
wire [7:0] data_in;
reg [7:0] data_out; //use reg type, but not registers
wire [7:0] decode_out;
wire [7:0] cnt_out;
always @(decode_out or cnt_out or sel1 or sel2 or sel3) begin
case ({sel1, sel2, sel3})
3'b100: data_out = decode_out;
3'b010: data_out = cnt_out;
3'b001: data_out = 8'b11111111;
default: data_out = 8'bZZZZZZZZ;
default: data_out = 8'bZZZZZZZZ;
endcase
end
assign data_bus = data_out;
assign data_bus = data_out;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -590,26 +589,26 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
/******************************
三态实例中调用的子模块
******************************/
module counter (clock,
reset,
data_bus_in,
cnt_out
);
input clock, reset;
input [7:0] data_bus_in;
output [7:0] cnt_out;
reg [7:0] cnt_out;
always @(posedge clock or posedge reset)
if (reset)
cnt_out <= 8'b00000000;
else
cnt_out <= data_bus_in + 1;
endmodule
```
@@ -617,17 +616,17 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
/******************************
三态实例中调用的子模块
******************************/
module decode (clock, reset, data_bus_in, addr_bus, data_bus_out);
input clock, reset;
input [7:0] data_bus_in;
input [7:0] addr_bus;
output [7:0] data_bus_out;
reg [7:0] data_bus_out;
always @(posedge clock or posedge reset)
if (reset)
data_bus_out <= 8'b00000000;
@@ -638,7 +637,7 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
8'b 10100000: data_bus_out <= 8'b11111111;
default: data_bus_out <= data_bus_in;
endcase
endmodule
```
@@ -647,43 +646,43 @@ RTL 描述中时序逻辑和组合逻辑的连接关系和拓扑结构决定了
mux 也是一种组合逻辑电路,它的常用建模方式也有两种:对于简单的 mux,可以直接用 `assign` 和 `?` 表达式建模,对于复杂的 mux,则需要使用 `always` 和 `if ... else`、`case` 等条件判断语句建模。
1. **简单的 mux 用 `?` 表达式建模。信号被定义为 `wire` 型,`?` 表达式的判断条件是的选择端。**
```verilog mux.v
/******************************
使用"?"表达式描述一个 2 选 1 的 mux。
******************************/
module mux (en, a, b, mux_out);
input en;
input a, b;
output mux_out;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
wire mux_out;
assign mux_out = (en)? a : b;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
2. **复杂的 mux 用 `case` 或嵌套的 `if ... else` 建模。信号被定义为 `reg` 型,每个`case` 或 `if ... else` 的条件分支即一路 mux 的选择输出。**
```verilog
/******************************
使用 case 描述一个 4 选 1 的 mux。
******************************/
// mux2.v
module mux2 (en, a, b, c, d, mux_out);
input [1:0] en;
input a, b, c, d;
output mux_out;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg mux_out;
always @(en or a or b or c or d)
case(en)
2'b00: mux_out = a;
@@ -692,7 +691,7 @@ mux 也是一种组合逻辑电路,它的常用建模方式也有两种:对
2'b11: mux_out = d;
endcase
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -744,8 +743,8 @@ always @(posedge clk)
if (WR && CS) // write
RAM8x64 [addr] <= data_in [7:0];
else if (~WR && CS) // read
mem_data <= RAM8x64 [addr];
mem_data <= RAM8x64 [addr];
assign data_out = (en)? mem_data[7:0] : {~mem_data[7], mem_data[6:0]};
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
@@ -769,57 +768,57 @@ endmodule
一般来说,PLD 中的**主要时钟处理为分频和移相**。偶数分频十分简单,只需用高速时钟做一个同小计数器,然后在相应的位抽头即可。奇数分频电路相对复杂一些。移相的基本方法是通过高速时钟调整相位,或者通过时钟反向调整相位。
1. **偶数分频 + 相位控制**
```verilog clk_div_phase.v
/******************************
将一个 200kHz 时钟做 2 分频、4 分频、8 分频, 要求分频后的 3 个时钟同相, 而且与源时
钟近似同相。在这个设计中, 因为输入时钟速率很低, 仅有 200kHz, 而一般 PLD 内嵌的 PLL
钟近似同相。在这个设计中, 因为输入时钟速率很低, 仅有 200kHz, 而一般 PLD 内嵌的 PLL
的输入频率下限都在 MHz 级,所以无法使用 PLL 完成分频与相位调整要求。另外对于低速时
钟的分频,使用计数器既能满足时序要求,也比较节约器件资源。
******************************/
module clk_div_phase (rst, clk_200K, clk_100K, clk_50K, clk_25K);
input clk_200K;
input rst;
output clk_100K, clk_50K, clk_25K;
wire clk_100K, clk_50K, clk_25K;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [2:0] cnt;
reg [2:0] cnt;
always @ (posedge clk_200K or negedge rst)
if (!rst)
cnt <= 3'b000;
else
cnt <= cnt + 1;
assign clk_100K = ~cnt [0];
assign clk_50K = ~cnt [1];
assign clk_25K = ~cnt [2];
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
这个设计的**难点在于如何调整所有时钟的相位关系**。本例巧妙地通过对计数器每个 bit 的反向,完成了所有分频后时钟的相位调整,保证了3个分频后时钟的相位严格同相。对硬件结构比较清晰则会发现,这 3 个派生时钟与源时钟相比有一个非常小的相位差,**这个相位差是由寄存器的固有 $T_{\mathrm{co}}$(延迟)和计数器累加的组合逻辑造成的**,一般来说在 PLD 中寄存器固有 $T_{\mathrm{co}}$ 的典型值为 1~2ns,而简单的加法运算的组合逻辑门延迟也约为 ns 级,这两个延迟的总和与时钟周期相比微乎其微。如果忽略这个 ns 级的延迟,则通过每个分频时钟的反向,使 3 个分频时钟与源时钟同相,也就是说这 4 个时钟有共同的上升沿。
2. **奇数分频**
```verilog clk_3div.v
/******************************
对源时钟做 3 分频, 要求 3 分频时钟占空比为50%。
******************************/
module clk_3div (clk, reset, clk_out);
input clk, reset;
output clk_out;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
reg [1:0] state;
reg clk1;
always @(posedge clk or negedge reset)
if(!reset)
state <= 2'b00;
@@ -829,18 +828,18 @@ endmodule
2'b01: state <= 2'b11;
2'b11: state <= 2'b00;
default:state <= 2'b00;
endcase
endcase
always @(negedge clk or negedge reset)
if(!reset)
clk <= 1'b0;
else
clk1 <= state[0];
assign clk_out = state[0] & clk1;
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
endmodule
```
3 分频、5 分频等奇数分频时钟可以使用 `case` 结构或简单的状态机(FSM)描述,设计**难点在于如何通过组合逻辑调整分频时钟的占空比。**
@@ -894,14 +893,14 @@ endmodule
/******************************
同步复位电路建模。
******************************/
module syn_rst (clk, rst_, cnt1, cnt2);
input clk;
input rst_;
output [4:0] cnt1 , cnt2;
reg [4:0] cnt1 , cnt2;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
always @(posedge clk)
if (!rst_) begin
@@ -912,11 +911,11 @@ endmodule
if (cnt1 < 2'b11)
cnt1 <= cnt1 + 1;
else
cnt1 <= cnt1;
cnt2 <= cnt1 - 1;
cnt1 <= cnt1;
cnt2 <= cnt1 - 1;
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -942,7 +941,7 @@ endmodule
#### 3.9.1.3. 同步复位的缺点
- 很多目标器件(如 FPGA 和 CPLD)和 ASIC 库的触发器本身并不包含同步复位端口,使用同步复位会增加更多逻辑资源。
- 同步复位的最大问题在于必须保证复位信号的有效时间足够长,从而才能保证所有触发器都有效地复位。由于仅当时钟沿采样到复位信号时才会进行复位操作,所以**同步复位信号的持续时间起码要大于设计的最长时钟周期**,以保证所有时钟的有效沿都能采样到同步复位信号。其实仅仅保证同步复位信号的持续时间大于最慢的时钟周期还是不够的,设计中**还要考虑到同步复位信号树通过所有相关组合逻辑路径的延时以及由于时钟布线产生的偏斜(skew)**,只有同步复位大于时钟最大周期加上同步信号穿过的组合逻辑路径延迟加上时钟偏斜时,才能保证同步复位可靠、彻底。同步复位实现结构如下图所示,假设同步复位逻辑树组合逻辑的延时为 $\mathtt{t1}$,复位信号传播路径的最大延迟为 $\mathtt{t2}$,最慢时钟的周期为 $\mathtt{Period max}$,时钟的 skew 为 $\mathtt{(clk2 - clk1)}$,则同步复位的周期 $\mathtt{Tsyn\_rst}$ 应该满足下述公式:
$$
\mathtt{Tsyn\_rst > Period max + \left(clk2 - clk1 \right) + t1 + t2}
@@ -958,19 +957,19 @@ $$
#### 3.9.2.1. 异步复位电路建模
1. 指定异步复位时,只需在 `always` 的敏感表中加入复位信号的有效沿即可,当复位信号有效沿到达时,无论时钟沿是否有效,复位立即发挥功能。
```verilog asyn_rst.v
/******************************
异步复位电路建模。
******************************/
module asyn_rst (clk, rst_, cnt1, cnt2);
input clk;
input rst_;
output [4:0] cnt1 , cnt2;
reg [4:0] cnt1 , cnt2;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
always @(posedge clk or negedge rst_)
if (!rst_) begin
@@ -981,11 +980,11 @@ $$
if (cnt1 < 2'b11)
cnt1 <= cnt1 + 1;
else
cnt1 <= cnt1;
cnt2 <= cnt1 - 1;
cnt1 <= cnt1;
cnt2 <= cnt1 - 1;
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
endmodule
```
@@ -999,23 +998,23 @@ $$
#### 3.9.2.2. 异步复位的优点
- 由于多数目标器件(如FPGA 和 CPLD)和 ASIC 库的触发器都包含异步复位端口,异步复位会节约逻辑资源。
- 异步复位设计简单。
- 对于大多数 FPGA, 都有专用的全局异步复位/置位资源(GSR, Global Set Reset),使用GSR 资源,异步复位到达所有寄存器的偏斜(skew)最小。
#### 3.9.2.3. 异步复位的缺点
- 异步复位的作用和释放与时钟沿没有直接关系,在异步复位生效时问题并不明显,但是当异步复位释放时,如果异步复位信号释放时间和时钟的有效沿到达时间几乎一致,则容易造成触发器输出为**亚稳态**,造成逻辑错误。
- 另外,如果异步复位逻辑树的组合逻辑产生了**毛刺**,则毛刺的有效沿会使触发器误复位,造成逻辑错误。
#### 3.9.2.4. 推荐的复位电路设计方式
1. 推荐的复位电路设计方式是异步复位,同步释放。这种方式,可以有效地继承异步复位设计简单的优势,并克服异步复位的上述风险与缺陷。
2. 在 FPGA/CPLD 等可编程逻辑器件设计中,使用异步复位,同步释放可以节约器件资源,并获得稳定可靠地复位效果,是推荐的复位设计方式。
```verilog asyn_rst_syn_release.v
/******************************
异步复位,同步释放电路建模。异步复位,同步释放的具体设计方法很多,关键是如何保证同步
@@ -1046,8 +1045,8 @@ always @(posedge clk or negedge reset_reg)
if (cnt1 < 2'b11)
cnt1 <= cnt1 + 1;
else
cnt1 <= cnt1;
cnt2 <= cnt1 - 1;
cnt1 <= cnt1;
cnt2 <= cnt1 - 1;
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
@@ -1122,7 +1121,7 @@ always @(a or b or c or d or sel0 or sel1 or sel2 or sel3) begin
else if (sel1)
z = b;
else if (sel0)
z = a;
z = a;
end
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
+17 -19
View File
@@ -19,9 +19,7 @@ tags:
- 速度
- 面积
categories:
- - Verilog
- - Josh 的学习笔记
- Verilog
- [Josh 的学习笔记, Verilog]
abbrlink: 53b8b42e
date: 2020-12-05 00:46:00
---
@@ -111,11 +109,11 @@ input Clk; // 设计的主时钟
input Reset; // 异步复位
input FhtStarOne,FhtStarTwo,FhtStarThree,FhtStarFour;
// 4 个单步算法的时序控制信号
// FHT 的 16 个输入
input [11:0] I0,I1,I2,I3,I4,I5,I6,I7,I8;
input [11:0] I9,I10,I11,I12,I13,I14,I15;
input [11:0] I9,I10,I11,I12,I13,I14,I15;
// FHT 的 16 个输出
output [15:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7;
output [15:0] Out8,Out9,Out10,Out11,Out12,Out13,Out14,Out15;
@@ -196,7 +194,7 @@ input FhtStar; // 单步 FHT 运算控制信号
// 单步 FT运算输入
input [11:0] In0,In1,In2,In3,In4,In5,In6,In7,In8,In9;
input [11:0] In10,In11,In12,In13,In14,In15;
// 单步 FT运算输出
output [12:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,Out9;
output [12:0] Out10,Out11,Out12,Out13,Out14,Out15;
@@ -294,13 +292,13 @@ wire [15:0] Temp8,Temp9,Temp10,Temp11,Temp12,Temp13,Temp14,Temp15;
reg [2:0] Cnt3; //count from 0 to 4,when Reset Cnt3=7;
reg FhtEn; //Enable fht culculate
always @(posedge Clk or negedge Reset) begin
always @(posedge Clk or negedge Reset) begin
if (!Reset)
Cnt3<= #1 3'b111;
Cnt3<= #1 3'b111;
else begin
if (PreFhtStar)
Cnt3<= #1 3'b100;
else
else
Cnt3<= #1 Cnt3-1;
end
end
@@ -315,7 +313,7 @@ else begin
FhtEn<= #1 0;
end
// 补码运算, 复制符号位
// 补码运算, 复制符号位
assign Temp0 = (Cnt3 == 4) ? {In0[11],In0[11],In0[11],In0[11],In0} :Out0;
assign Temp1 = (Cnt3 == 4) ? {In1[11],In1[11],In1[11],In1[11],In1} :Out1;
assign Temp2 = (Cnt3 == 4) ? {In2[11],In2[11],In2[11],In2[11],In2} :Out2;
@@ -358,7 +356,7 @@ always @(posedge Clk or negedge Reset) begin
Out14[15:0] <= #1 Temp7[15:0] + Temp15[15:0];
Out15[15:0] <= #1 Temp7[15:0] - Temp15[15:0];
end
end
end
end
endmodule
@@ -595,13 +593,13 @@ case (var)
1. 通过 Buffer 等组合逻辑延迟线调整采样时间
在早期逻辑电路图设计阶段,有一些设计者养成了手工加入 Buffer 或者非门调整数据延迟的习惯,从而保证本级模块的时钟对上级模块数据的建立、保持时间的要求。这些做法目前主要应用的场合有两种:一是使用分立逻辑元件(如 74 系列)搭建数字逻辑电路;另一种是在 ASIC 设计领域。**目前使用分立逻辑元件搭建数字逻辑电路的场合一般为系统复杂度相对较低,系统灵活性要求不高的场合。**在上述场合使用分立逻辑器件设计数字逻辑电路,由于可以使用的调整延时的手段相对有限,而且采用插入 Buffer 、数字延迟逻辑甚至两个非门等手段调整采样的 Setup 和 Hold 时间是可以接受的。而 ASIC 设计领域采用这种方法是以严格的仿真和约束条件作为强力支持的。
正如 [2.1 同步设计原则](#0201)所述,**使用组合逻辑方法产生延迟,容易产生毛刺**,而且这种设计方法的**时序余量较差**,一旦外界条件变换(环境试验,特别是高低温试验),采样时序就有可能完全紊乱,造成电路瘫痪。另外,一旦芯片更新换代,或者移植到其他器件族的芯片上,采样时延必须重新调整,电路的可维护性和继承性都很差。
2. 盲目使用时钟正负沿调整数据采样
很多初学者习惯随意使用时钟的正负沿调整采样,甚至产生一系列不同相位或不同占空比的时钟,使用其正负沿调整数据。这种做法是不推荐的,原因如下:
1. 如果在一个时钟周期内,使用时钟的双沿同时操作,则使用该时钟的同相倍频时钟也能实现相同的功能。换句话说,一个时钟周期内,使用时钟的双沿同时操作,相当于使用了一个同相的倍频时钟。此时因为设计的时钟频率提升,所有相关的使用约束都会变得更紧,不利于可靠实现。
2. 芯片中的 PLL 和 DLL 一般都能较好地保证某个时钟沿的 Jitter、Skew 和占空比等各种参数指标,而对于另一个时钟沿的指标控制并不是那么严格。特别对于综合、实现等 EDA 的软件,如果没有明确对另外一个沿进行相关,这个沿的时序分析不一定完善,其综合或实现结果就不一定能严格满足用户期望的时序要求(比如 Setup、Hold 时间等),往往造成在该沿操作不稳定的结果。
@@ -609,7 +607,7 @@ case (var)
总结这两点,如果设计者并不十分清楚同时使用上下沿的方法,不如直接使用同相倍频时钟更加简单、明确、可靠。但是如果设计者十分清楚同一周期使用双沿的注意事项,附加了相应的约束,这种做法并非不可。
针对使用两个时钟沿,在这里还想补充以下两点:
- 使用者虽然使用了同一个时钟的两个沿,但是**保证不在同一个周期内同时使用双沿,则不会增加时钟频率**。
- DDR 、QDR 本身就是利用了上下沿采样的原理,随着存储器件高速发展,时钟速度已经成为存取器件的瓶颈,所以可用时钟上下沿操作缓解对单沿 RAM 时钟振荡器的要求。但是必须清楚,硬件的 DDR、QDR 电路(包括 ASIC 的 DDR、QDR 与 FPGA 内嵌的 DDR、QDR 电路)是专用高速设计电路,对时钟的正沿、负沿的 Jitter 、Skew 和占空比等指标都有详细和明确的要求,这一点是和普通逻辑设计,特别是实现在 FPGA 中设计的情况截然不同,希望读者加以区分。
@@ -618,16 +616,16 @@ case (var)
下面分别介绍 [2.3 小节](#0203)提出的两大类异步时钟域数据同步问题的解决方法。
1. 同频异相问题
同频异相问题的简单解决方法是**用后级时钟对前级数据采样两次**,即通常所述的**用寄存器打两次**。数据同步如[图 5-10](#图5-10) 所示,这样的做法是有效地减少了亚稳态的传播,使后级电路数据都是有效电平值。但是这种做法并不能保证两级寄存器采样后的数据是正确的电平值,因为一旦 Setup 或 Hold 时间不满足,采样发生亚稳态,则经判决时间(Resolution Time)后,还是可能判决到错误电平值。所以这种方法仅仅适用于对少量错误不敏感的功能单元。
<a name="图5-10"></a>
<div align="center">
<img src="https://josh-blog-1257563604.cos.ap-beijing.myqcloud.com/img/2020-12-05-josh-verilog-part-5/2020-12-05-josh-verilog-part-5-100-DataSynchronization.png!sign" width="700px" alt="数据同步"/>
</div>
可靠的做法是用 DPRAM 、FIFO 或者一段寄存器 Buffer 完成异步时钟域的数据转换。把数据存放在 DPRAM 或FIFO 的方法如下:将上级芯片提供的数据随路时钟作为写信号,将数据写入 DPRAM 或者FIFO, 然后使用本级的采样时钟( 一般是数据处理的主时钟),将数据读出即可。由于时钟频率相同,所以 DPRAM 或 FIFO 两端的数据吞吐率一致,实现起来相对简单。
2. 异频问题
可靠完成异频问题的解决方法就是使用 DPRAM 或 FIFO 。其实现思路与前面所述一致,用上级随路时钟写上级数据,然后用本级时钟读出数据。但是由于时钟频率不同,所以两个端口的数据吞吐率不一致,设计时一定要开好缓冲区,并通过监控(Full、Half、Empty 等指示)确保数据流不会溢出。
@@ -702,7 +700,7 @@ case (var)
5. **将存储逻辑独立划分成模块**
RAM、ROM、CAM 和 FIFO 等存储单元应该独立划分模块。这样做的好处是便于利用综合约束属性显化指定这些存储单元的结构和所使用的资源类型,也便于综合器将这些存储单元自动类推为指定器件的硬件原语。另一个好处是在仿真时消耗的内存也会减少,便于提高仿真速度。这是因为大多数仿真器对大面积的RAM都有独特的内存管理方式,以提高仿真效率。
6. **合适的模块规模**
从理论上讲,模块的规模越大,越利于模块资源共享(Resource Sharing)。但是庞大的模块,将要求对综合器同时处理更多的逻辑结构.这将对综合器的处理能力和计算机的配置提出了较高的要求。另外,庞大的模块划分,不利于发挥目前非常流行的增拭综合与实现技术的优势。
@@ -2,7 +2,7 @@
title: 'Josh''s Notes: SystemVerilog 验证 (Part 1 — 验证导论)'
mathjax: true
comments: true
copyright: false
copyright: true
sticky: false
toc:
enable: true
@@ -2,7 +2,7 @@
title: 'Josh''s Notes: SystemVerilog 验证 (Part 2 — 数据类型)'
mathjax: true
comments: true
copyright: false
copyright: true
sticky: false
toc:
enable: true
@@ -2,7 +2,7 @@
title: 'Josh''s Notes: SystemVerilog 验证 (Part 3 — 过程语句和子程序)'
mathjax: true
comments: true
copyright: false
copyright: true
sticky: false
toc:
enable: true
@@ -4,7 +4,7 @@ tags:
- 牛津5000
- 英语词汇
comments: true
copyright: false
copyright: true
toc:
enable: true
number: true
+1 -1
View File
@@ -4,7 +4,7 @@ tags:
- 牛津5000
- 英语词汇
comments: true
copyright: false
copyright: true
toc:
enable: true
number: true